Git使用教程
Git是目前世界上最先进的分布式版本控制系统
git init
git clone username@host:/path/to/repository
git add * //添加到缓存区
git commit -m "代码提交信息" //本地仓库HEAD
git push origin master //提交到远端分支
git remote add origin <server> //将本地仓库连接到远程服务器
git checkcout -b feature_x //创建一个名为feature_x的分支
git branch -d feature_x //删除新建的分支
git push origin <branch> //将分支推送到远端仓库
git pull //更新本地仓库到最新改动
git merge <branch> //合并其他分支到当前分支
git add <filename> //标记为合并成功
git diff <source_branch> <target_branch> //对比
git tag 1.0.0 1b2e1d63ff
git log
git checkout -- <filename> //替换掉本地改动
git fetch origin
git reset --hard origin/master //丢弃本地的改动
git push origin :feature_x //删除远程分支
2020-02-28
网络通信模块 AFURLSessionManager、AFHTTPSessionManager
网络状态监听模块 Reachability
网络通信安全策略模块 Security
网络通信信息序列化/反序列号模块 Serialization
对于iOS UIKit库的扩展
调用父类的初始化方法
检测URL有值且最后一位不包含/,需要加上/
保存baseURL
请求序列对象、响应序列对象
quene并发线程数设置为1
各种响应转码
设置默认安全策略
加锁,确保多线程访问安全
置空task关联的代理
初始化一些属性,包括
mutableTaskDelegatesKeyedByTaskIdentifier 让每一个请求Task和我们自定义的AF代理建立映射用的
异步获取当前当前session的所有未完成的task 防止后台回来重新初始化这个Session,一些之前的后台请求任务,导致程序崩溃
生成一个Task,然后开始网络请求
将参数和各种东西转化为一个NSMutableURLRequest
如果解析错误,那么直接返回
用self.requestSerializer和各种参数去获取了一个我们最终请求网络需要的NSMutableURLRequest实例,并且在完成的回调里,调用我们传过来的成功和失败的回调
将request的各种属性循环遍历
将传入的参数进行编码并且添加到request中
AFHTTPRequestSerializerObservedKeyPaths() 是一个C函数返回一个数组
这个函数主要是封装了一些属性的名字 这些都是NSURLRequest的属性
self.mutableObservedChangedKeyPaths
在init方法对这个集合进行了初始化,并且对当前类的和NSURLRequest的相关属性进行了KVO监听
当观察到这些set方法被调用了,而且不为Null就会添加到集合里,否则移除
这个属性其实是我们自己设置的request属性的集合
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
用KVC的方式,把属性值都设置到我们请求的request中去
将传入的参数进行编码,并且设置到request中去
判断该Request中是否包含了GET,HEAD,DELETE。POST、PUT是把query拼接到Http body中的
设置请求头、请求体
从自己的head里去遍历,如果有值则设置给request的head
把各种类型的参数,array,dic,set转化成字符串,给request
具体怎么实现容器类型的参数转换为字符串类型的参数
紧接着根据请求类型,判断参数字符串如何设置到request中去。如果是GET、HEAD、DELETE,则把参数query拼接到url的后面。而POST、PUT是吧query拼接到http body中
完成初始化方法
生成一个request
调用父类的生成Task方法,并且执行了一个成功和失败的回调
创建NSURLSessionDataTask
为什么用同步,因为想要主线程等在这,执行成功再返回,只有执行完dataTask才有数据,传值才有意义
为什么要用串行队列,防止iOS8以下内部的dataTaskWithRequest是并发创建的,会导致taskIdentifiers这个属性值不唯一,因为后续要用taskidentifiers来做为key对应delegate
保证即使在多线程的环境下,也不会创建其他队列
为什么不直接调用 dataTask = [self.session dataTaskWithRequest:request] 为了适配iOS8以下,创建session的时候,偶发的情况会出现session的属性taskIdentifiers这个值不唯一,而这个taskIdentifiers是为了后来我们映射delegate的key,所以他必须是唯一的。
AFURLSessionManagerTaskDelegate和AFURLSessionManager建立相互关系
设置AF delegate 的上传进度块,下载进度块
加锁,保证字典线程安全
为AF delegate 设置task的progress监听
添加task开始和暂停的通知
如果task触发KVO,则给progress进度赋值,因为赋值了,所以会触发progress的KVO,也会调用到这里,然后执行我们传进来的downloadProgress 和uploadProgressBlock 为了让进度实时的传递
线程、锁、性能各方面权衡
1、初始化动画,并设置动画属性
2、设置动画属性初始值、结束值、以及其他属性
3、绘图层添加动画
Core Animation
核心动画:基础动画、关键帧动画、动画组、转场动画
将基础动画添加到动画组,最后将动画组添加到图层
CABasicAnimation
CAKeyframeAnimation
创建转场动画
设置转场类型、子类型及其他属性
设置转场后的新视图并添加动画到图层
旋转动画
创建动画并定制动画属性
设置动画属性初始值、结束值
设置其他动画属性
添加动画到图层,注意key相当于给动画进行命名,以后获得动画时可以使用此名称
图层动画的本质就是将图层内部的内容转化为位图,经硬件操作形成一种动画效果,其实图层本身没有任何变化,上面的动画中图层并没有因为动画效果而改变他的位置。对于缩放动画其实大小也是不会改变的,所以动画完成后图层还是在原来显示的位置没有任何变化。如果这个图层在一个UIView中你会发现在UIView移动的过程中,你要触发UIView的点击事件也只能点击原来的位置。因为他的位置从来没有改变过
核心动画有一个媒体时间的概念,假设将一个旋转动画设置旋转一周用时60秒的话,那当动画旋转90度后媒体时间就是15秒,如果此时要将动画暂停,只需要让媒体时间偏移设置为15秒即可。并把动画运行速度设置为0使其停止运动。类似的,如果又过了60秒后需要回复动画。这是只要将动画开始时间设置为当前媒体时间75秒减去暂停时的时间。那么动画就会冲
Workspace,Static Library,Framework,Objective-C,Swift
iOS Workspace项目管理
1、创建Workspace工作空间
2、在桌面新建文件夹做为根目录,命名为School。将步骤1创建的工作空间命名为School.xcworkspace,并保存到School文件夹里面。
3、创建第一个工程命名为Student,并将工程添加到School工作空间。
4、重复步骤3,创建第二个工程命名为Teacher,并将工程添加到School工作空间。
5、重复步骤3,创建第三个工程命名为Parent,并将工程添加到School工作空间。
6、创建完成后,School目录和School.xcworkspace工程结构如下图所示
7、创建Static Library,命名为SchoolLib,同上步骤添加到School.xcworkspace里,具体步骤如下:
8、创建Framework静态库,命名为SchoolFramwork,图示步骤如下:
9、至此,我们创建完成了三个工程(Student,Teacher,Parents)和两个静态库(SchoolLib,SchoolFramework)。
10、最终School文件目录结构如下图:
11、工程中引用Static Library库
12、首先在SchoolLib.h文件中写一个类方法,我们希望这个方法可以在Parent工程里调用。
13、如果想要在Parent工程里调用,我们首先需要把SchoolLib静态库和Parent工程进行关联,步骤如下:
14、如果此时引入静态库后,编译代码仍旧是不能够通过的,我们需要将静态库的目录引用进来
15、在Teacher工程的Target/Build Settings/User Header SearchPaths中添加$(BUILT_PRODUCTS_DIR),并选择递归引用
16、此时我们就可以在Parent工程中引用SchoolLib静态库了,图示如下:
17、工程中引用SchoolFramework库
18、在SchoolFramework中新建一个测试类,并且公开一个测试方法:
19、在SchoolFramework.h文件中公开测试类的.h文件
20、此时,我们还不能在具体的工程中去引用,我们还需要在Teacher/Targets/Build Phases/Link Binary with Libraries里面添加自定义的framework:
21、在Teacher/Targets/General/Embedded Binaries这里添加自定义的framework
22、SchoolFramework里写的类如果需要在Teacher工程中只引入框架就可以使用,需要在SchoolFramework/Targets/Build Phases里将Project里的头文件移动到Public里的分组中。
23、至此、我们可以在Teacher工程中测试调用SchoolFramework库中定义的方法
24、工程中引入CocoaPods管理
25、终端进入工程根目录下,创建Podfile文件
26、用Vim打开Podfile文件,输入如下结构的内容。
27、执行pod install 命令,引入指定的第三方库。
28、最终的School.xcworkspace工程结构如下图所示:
29、Student工程和Teacher工程的相互引用
30、如果要在项目Studnet中引用Teacher中的内容,那么我们需要修改路径
31、在Student的Build Settings里找到Header Search Paths,添加一项Teacher工程的路径。可以直接将Teacher工程拖过来,Xcode会自动生成路径,并且设置为recursive。
32、在Teacher中创建一个测试类,并添加一个测试方法
33、在Student工程中的ViewController.m中需要同时引入在Teacher工程中创建测试类的.h文件和.m文件
34、最终在Student工程中成功的调用了Teacher工程中测试类的类方法,如下图所示
35、Objective-C和Swift混编:Objective-C调用Swift函数
36、在一个Objective-C项目中第一次创建一个Swift文件的时候,Xcode会提示是否需要创建一个桥接头文件,点击是之后Xcode会自动创建一个桥接文件,文件名为xxxx-Bridging-Header.h
37、需要在OC类中引入头文件,文件格式为 Parent-Swift.h
38、新建一个测试类SecondVC.swift,在SeconVC.swift中定义一个测试方法,如下图所示。然后进行调用。
39、运行代码,会发现调用成功。
40、Objective-C和Swift混编:Swift调用Objective-C方法
41、新建测试类FirstVC,如下图所示,定义一个测试方法
42、在桥接文件中引入FirstVC.h头文件
43、运行代码,会发现调用成功
44、注意事项如下图
完。
2020-02-26 CoreData,CLLocation,Itms-Service 学习
itmsServices 是苹果推出的一款协议,基于这款协议,我们在本地部署一个服务器,将ipa包存放到本地服务器,然后测试人员只要通过Safari浏览器访问特定的地址,就可以通过内网更新App
注意事项
1、项目打包后的文件、使用企业分发方式打出的一个xxx.ipa包
2、一个plist文件,内容如下。
3、由于xxx.plist文件的访问地址必须是https,我们需要将plist文件存放到github上,所以还需要一个github账号
4、下载的测试机,部署的服务器需要连接同一个内网
5、用测试机通过Safari浏览器输入如下地址,然后下载
其中,参数1是IOS工程的根路径,是必输项。参数2可以不输入,是可选的,含义是编译时的工程configuration类型,有4种类型可选:Debug, AdHoc,Release, Distribution。默认是Release。
ipa-build脚本运行后,会在IOS工程根路径下生成名为“build”的文件夹,在这个文件夹中又有一个名为“ipa-build”的文件夹,打包所生成的最新ipa包就在其中。
最终生成的地址格式如下
itms-services://?action=download-manifest&url=https://raw.githubusercontent.com/wangbinji/StopCar/master/down.plist
Plist文件格式如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>http://xxxxxxxxxxxxxxxxxxx/xxx.ipa</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http://xxxxxxxxxxxxxxxxxx.png</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http://xxxxxxxxxxxxxxxxxx.png</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.xxxx.demo</string>
<key>bundle-version</key>
<string>1.0.0</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>XXXX App download</string>
</dict>
</dict>
</array>
</dict>
</plist>
CoreData
CoreData 苹果自己推出的数据存储框架,采用了一种ORM(对象关系映射)的存储关系
数据库数据与Objective-C对象相互转换
NSManagedObjectContext 托管对象上下文,数据库的大多数操作是在这个类操作
NSManagedObjectModel 托管对象模型,其中一个托管对象模型关联到一个模型文件,里面存储着数据库的数据结构
NSPersistentStoreCoordinator 持久化存储协调器 主要负责协调上下文与存储的区域的关系
NSManagedObject 托管对象类,其中CoreData里面的托管对象都会继承此类
- Integer 16 代表整数,范围是 -32768 ~ 32767
- Integer 32 代表整数,范围是 -2147483648 ~ 2147483647
- Integer 64 代表整数,范围是 -9223372036854775808 ~ 9223372036854775807
- Double 代表小数
- Float 代表小数
- String 代表字符串, NSString表示
- Boolean 代表布尔值,使用NSNumber表示
- Data 代表日期时期
- Binary Data 代表二进制,使用NSData表示
- Transformable 代表Objective-C对象,要遵守NSCopying协议
CLLocation
- 1、静止不动
上一个GPS点的瞬时速度为零,当前点的瞬时速度也为零,那么当前点无效,瞬时速度就是CLLocation的属性speed - 2、GPS信号太差
信号是CLLocation的属性horizontalAccuracy,表示水平方向的误差值,当这个值大于70,认为信号差。 - 3、无效移动
前后两个GPS点的距离小于horizontalAccuracy*(0.5-0.66),我们认为这个点是无效移动 - 4、平均速度过大
当前点到上一个点的距离/当前点到上一个点的时间 速度大于某一个值,则认为当前点无效 - 5、采样频率
distanceFilter = 30 只有超过30米的移动,才会进入到位置更新的回调方法。省电、CPU占用低
如何通过无线的方式进行真机调试
开发iOS一年了,每次都是通过数据线连接的方式进行真机调试。我是一个非常的追求简约的人,各种数据线是能不用就不用,之前一直以为不能通过无线的方式调试应用。今天闲来无事,在苹果开发者官网看WWDC视频,看了苹果XCode的开发人员介绍XCode的用法,很细致,讲解的也很清楚,示例虽然简单,但是把XCode的方方面面都讲到了。创建一个项目、查看开发者文档、单元测试、UI测试。讲解到调试的时候,虽然他是通过数据线方式进行调试的,但他顺带的提了一句你也可以通过无线的方式调试。我立刻就去研究了一下,发现原来确实是可以通过无线的方式调试的,只要MAC和iPhone在同一个WiFi环境下就可以。很让我感慨啊,感慨什么呢?我感慨学习知识还是要从知识的源头去获取。
Do not just seek happiness for yourself. Seek happiness for all. Through kindness. Through mercy.
NEW: DevDocs now comes with syntax highlighting. http://devdocs.io
1 | [rectangle setX: 10 y: 10 width: 20 height: 20]; |
未命名
VPN virtual page number 虚拟页表条目
VPO virtual page offset 虚拟页面偏移
PPN physical page number 物理页表条目
PPO physical page offset 物理页面偏移
TLBI TLB索引
TLBT TLB标记
CO 缓冲块内的字节偏移量
CI 高速缓存索引
CT 高速缓存标记
PA physical address 物理地址
VA virtual address 虚拟地址
虚拟地址空间中的地址数量 N = 2^n
物理地址空间中的地址数量 M = 2^m
页的大小(字节) P = 2^p
计算机系统漫游
凡事预则立,不预则废。自本人购买深入理解计算机系统一书以来,4月有余。泛泛的浏览了一遍,但深感学习的不扎实。遂决定自今日始,写小文章记录自己对此书的学习过程。力求在接下来的工作和生活中,对此书能有一个略微扎实的掌握,不负自己的初心。
开篇作者讲述了通过学习计算机系统对自己编程有哪些帮助。举了如下的例子:
- 避免由计算机表示数字的方式引起奇怪的数字问题。
- 通过一些小窍门来优化自己的C代码,以充分利用现代处理器和存储器系统的设计。
- 了解编译器是如何实现过程调用的,以及如何利用这些知识来避免缓冲区溢出错误带来的安全漏洞。
- 学会如何编写自己的Unix shell、自己动态存储分配包、甚至于自己的Web服务器。
- 会认识并发带来的希望和陷阱。
一、引言
作者在介绍完学习这本书我们会有哪些收获后,开始了本章的第一部分内容,介绍了最经典的“Hello world”程序的完整生命周期,这对一个程序员了解自己编写的程序是很有帮助的。下面就对一个由C语言编写的Hello world程序进行描述:
程序示例代码如下
##############################################################################
#include <stdio.h>
int main()
{
printf(“hello, world\n”);
return 0;
}
#############################################################################
总的描述这个程序的执行过程为:
- 首先被程序员创建
- 到系统上运行
- 输出简单的消息
- 然后终止
作者指明将沿着这个程序的生命周期,简要的介绍一些逐步出现的关键概念、专业术语、和组成部分
程序员首先用编辑器创建的Hello.c程序被称为源程序。源程序实际上是一个由0和1组成的位序列。8个位被组成为一组,称为字节。每个字节表示程序中的某些文本字符。这些文本字符在大多数的计算机系统上都是由ASCII标准表示的。有点需要注意的是:每个文本行都是以一个看不见的换行符‘\n’来结束的。有ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件。
作者在这里提出了一个基本的思想:系统中所有的信息————包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。
C编程语言的起源:
C语言是贝尔实验室的Dennis Ritchie于1969~1973年间创建的。后来C语言的标准化成了国际标注化组织的责任。这些标准定义了C语言和一些列函数库,即所谓的C标准库。Kernighan和Ritchie在他们的经典著作中描述了ASCII C。他们说到C语言是古怪的、有缺陷的、但同时也是一个巨大的成功。C语言主要有如下的三个特点:
* C语言与Unix系统关系密切。
* C语言小而简单
* C语言是为实践目的设计的。
C语言是系统级编程的首选,同时也非常的适用于应用级程序的编写。C语言的指针不易让人理解。同时,C语言缺乏对抽象的显示支持。例如类、对象和异常。
Hello.c程序的生命周期是从一个高级C语言程序开始的,因为这种形式能够被人读懂。但是呢、为了在系统上运行Hello.c程序,每条C语句都必须被其他程序转化为一系列的地低级机器语言指令。然后这些指令按照一种称为**可执行目标程序**的格式打包好,并以二进制磁盘文件的形式存放起来。目标程序也被称为**可执行目标文件**。
在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
linux> gcc -o hello hello.c
在这里,GCC编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello。这个翻译过程主要由四个阶段完成:
################################################################################
- 预处理阶段
预处理器根据以字符#开头的命令,修改原始的C程序。得到Hello.i - 编译阶段
编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,他包含一个汇编语言程序。 - 汇编阶段
汇编器(as)将hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中 - 链接阶段
连接器(ld)负责将printf.o合并到hello.o程序中。最后得到hello文件,它是一个可执行目标文件,可以被加载到内存中,由系统执行
#################################################################################
接下来作者告诉我们了解编译系统是如何工作的诸多好处
- 优化程序性能
一个switch语句是否比一系列的if-else语句高效? 一个函数调用的开销有多大?
while循环比for循环更有效吗? 指针引用比数组索引更有效吗?
*为什么将循环求和的结果放到一个本地变量中,会比将其放到一个通过引用传递过来的参数中,运行的更快? - 理解链接时出现的错误
链接器报告说无法解析一个引用,这是什么意思? 静态变量和全局变量的区别是什么?
静态库和动态库的区别是什么? 为什么有些链接错误直到运行时才会出现? - 避免安全漏洞
1.4 处理器读并解释存在内存中的指令