iOS编程读书笔记
Posted zcube
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS编程读书笔记相关的知识,希望对你有一定的参考价值。
11,22,23,24,25,28暂时不需要看
1 第一个简单的ios应用
- 单击按钮可以改变文字。
1.1 创建Xcode项目
- 创建项目的时候Xcode会提供一些包含通用代码的模版,可以根据需要选择模版。
- 创建项目是需要填写Organization Name和Company Identifier,也可以填入自己的公司名称和公司的反向域名。
- Class Prefix在Xcode 7.2创建项目里面已经没有了,或许是因为默认创建的项目类太少,但是自己在创建类的时候还是加上前缀为好,因为OC没有命名空间。
- 工作控件左侧是导航面板区域,中间是编辑区域。
1.2 模型-视图-控制器
- 简单介绍了MVC,下图清晰阐述了MVC中各模块扮演的角色。
1.3 设计Quiz
- 使用MVC思想,设计一个名叫Quiz的程序,实现单击按钮改变文字。
- 下面的应用对象图,勾勒出了对象之间的相互关系。
1.4 创建视图控制器
- 新版本Xcode会自动创建ViewController类了,且用storyboard文件来管理视图。
-
storyboard是多个xib文件集合的描述文件,也采用xml格式。那么storyboard与xib比较,区别在于:
- 一个工程中可以有多个xib文件,一个xib文件对应着一个视图控制器和多个视图。而使用storyboard时,一个工程只需要一个主storyboard文件就可以了。
- 在包含多个视图控制器的情况下,采用storyboard管理比较方便,而且storyboard还可以描述界面之间的导航关系。
-
Interface Builder一些介绍:
1.5 创建界面
- 单击main.storyboard编辑视图,画布中间的视图比较宽,可以在右侧属性面板将Use Auto Layout勾选掉。
- 通过Interface Builder在main.storyboard中添加Button和Label。
- 构建项目时main.storyboard会被编译为NIB文件,然后Xcode会将NIB文件拷贝到应用程序包(bundle)中,其实就是应用程序以.app结尾的后缀。
- 应用程序运行时会从程序包中按需载入NIB文件并激活文件中的对象。
1.6 创建关联
- 通过connection,一个对象可以知道另一个对象在内存中的位置,从而使这两个对象可以协同工作。
- Interface Builder中的两种关联:
- outlets:指向对象的指针变量。
- actions:动作方法,在视图对象和用户发生交互时会被调用。
- 新版本Xcode创建项目使用storyboard所以没有File's Owner,可以通过打开Assistant editor方便的关联对象:
- 创建关联在main.storyboard中的体现如下:
1.7 创建模型
-
ViewController对象创建完毕后会收到消息:
initWithNibName:bundle:
,所以可以在这里进行一些数据创建和初始化。- 不一定非得在
initWithNibName
中初始化数据,新版本Xcode创建的默认项目,使用initWithNibName
不会有效果,可以使用initWithCoder
。 - initWithNibName和initWithCoder的区别
- 不一定非得在
-
关于代码自动补全功能:
- 要实现模糊匹配可以安装FuzzyAutocomplete插件。
- 自动补全后会有一些占位符,如果要使用占位符,可以按回车即可。
1.8 其它
- AppDelegate应用程序委托是每个iOS应用都必须具备的启动入口。
- 新版本Xcode不需要在委托中添加代码,如果按照书中添加代码,会出现白屏。
- 模拟器中选择Simulator|Reset Content and Settings...可以将模拟器还原到默认设置并删除所有应用。
2 Objective-C
- 开发iOS应用使用Objective-C和Cocoa Touch框架.
2.1 对象
- Objective-C语言中,实例变量的变量名之前通常会加一个下划线,如_name,_date,_budget。
- 调用某个对象的方法,可以向对象发送相应的消息(message)。
2.2 使用对象
- 创建变量并进行初始化:
Party *partyInstance = [[Party alloc] init];
,将多个消息合并在一行的写法叫做嵌套消息发送(nested message send)。 - 消息发送代码各组成部分:
- 在Objective-C中,方法的唯一性取决于方法名,即使参数类型和返回类型不同,一个类也不能有两个名称相同的方法。
2.3 编写命令行工具PandomItems
- 不能在快速枚举
for in
中添加或删除对象,否则抛出异常。 - Objective-C格式字符串基本和C语言相同,
%@
对应的实参类型是指向任何一种对象的指针,通过覆盖description
方法定义格式化输出。
2.4 创建Objective-C类的子类
- Objective-C只允许单继承,所有的类都只能有一个父类。
- Objective-C保留了C语言的关键字,并增加了特有的关键字,新的关键字都用前缀@加以区分。
- Objective-C类中的存取方法名的规范为:
- 存方法命名规则为英文单词set加上要修改的实例变量名,以
_itemName
为例,存方法名为setItemName:
。 - 取方法名就是实例变量的变量名
itemName
,其它语言大多为:getItemName
。
- 存方法命名规则为英文单词set加上要修改的实例变量名,以
#import
和#include
的差别在于,#import
可以确保不会重复导入同一个文件。- 使用点语法存取变量例如
item.itemName
编译后和发消息一样,也是调用之前写好的存取方法,所以存取方法名要按照规范书写。Apple官方代码坚持使用点语法存取实例变量。 - 实例方法和类方法:调用实例方法时,需要向类的对象发送消息;调用类方法时,则向类自身发送消息。
-
使用存取方法访问实例变量是良好的编程习惯,即使是访问对象自身的实例变量,也应该使用存取方法,但是在初始化方法中例外。
-
初始化方法
- 每个初始化方法以英文单词
init
开头,Objective-C中命名约定很重要,应该严格遵守。 - 初始化方法的返回类型是
instancetype
,该关键字表示方法的返回类型和调用方法的对象类型相同。 - 在
instancetype
引入之前,初始化方法返回类型是id
,表示指向任意对象的指针,类似C语言的void*
。
- 每个初始化方法以英文单词
instancetype
和id
instancetype
只能用来表示方法返回类型,id
可以用来表示变量和方法参数类型。id
的定义是指向任意对象的指针,所以不需要再加*
,比如:id item
。
- 书中提到的指定初始化方法(designated initializer)不明白,根据书中后面的"其它初始化方法与初始化方法链的理解",指定初始化方法不同在于可以供其它初始化方法调用,但不调用其它初始化方法,通常参数最多。
self
和super
self
为类或对象自身,存在于方法中,是一个隐式(implicit)局部变量,相当于c++的this
。super
为父类,向super
发消息,其实就是向self发消息,但是要求系统再查找方法时跳过当前对象的类,从父类开始查询。
- 在初始化方法中应该直接访问实例变量,而不是使用存取方法。因为初始化方法执行时,无法确定新创建对象是否已经处于正确设置,所以应该直接访问类中实例变量。(其实这只是习惯问题)
-
初始化方法总结的若干规则:
- 类会继承父类所有的初始化方法,也可以加入其它初始化方法。
- 初始化方法要直接或间接调用父类的指定初始化方法。
- 其它初始化方法要直接或间接调用自身的指定初始化方法。
-
类方法的声明和实例方法的声明差别在于第一个字符,实例方法为
-
,类方法为+
。 - 在头文件中实例变量声明写在最前面,然后是类方法,接下来是初始化方法,最后是其它方法。这也是一种约定规范。
- 在Objective-C中,如果某个类方法的返回类型是这个类的对象(例如:
stringWithFormat:
),就可以将该类方法称为便捷方法(convenience method)。
2.5 深入学习NSArray与NSMutableArray
- Objective-C数组相关:
- 可以存储不同类型继承自
NSObject
的对象指针,不能保存基本C类型变量。 - 不能将
nil
加入数组,可以用NSNull
代替,例如:[items addObject:[NSNull null]];
。 - 访问数组可以使用下标语句
NSString *foo = items[0];
或发消息NSString *foo = [items objectAtIndex:0];
,这两种方法效果是相同的。
- 可以存储不同类型继承自
- 现在方括号的作用有3种:发送消息、存取方法、访问数组,如果使用点语法存取方法,下标语法访问数组,可以清晰突出发送消息代码。
- 在
NSMutableArray
中,可以使用下标语法向数组中添加和修改对象,等价于insertObject:atIndex:
和replaceObjectAtIndex:withObject:
发消息。
2.6 异常与未知选择器
对书中的疑惑:
- 书中意思是说所有类对象都是运行时绑定,但是感觉并不是所有OC对象都是运行时(runtime)绑定,除了书中展示的使用
id
来接收创建的对象时,这时候书中所说的isa
可能就不起作用了?
- 关于错误和异常处理:
2.12 如何为类命名
- OC没有提供命名空间机制,为了区分类,需要为类添加前缀。例如,开发一个MovieView应用,就可以在所有和项目相关的类名前加上MOV。
- Apple提供的类名都为2个字符前缀,为了减少与Apple未来发布类产生冲突的可能,我们要使用至少3个字符前缀。
2.13 #import和@import
@import Fundation
告诉编译器需要使用Foundation框架,之后编译器会优化预编译头文件和缓存编译结果过程,文件中不再明确引用框架,编译器会根据@import自动导入相应框架。- 目前只有Apple提供的框架可以使用@import,如果需要导入自己写的类和框架,只能使用
#import
。
新版本的Xcode已经不会自动创建预编译头文件,因为预编译头文件会带来代码复用困难等问题。
3 通过ARC管理内存
- 提出了"自动引用计数(automatic reference counting,ARC)"的概念。(涉及到自动管理资源的都会有引用计数的概念,类似C++智能指针)
- ARC和java的GC的区别是:ARC为编译时计算引用计数,GC在运行时计算。
3.1 栈
- 执行方法或函数是从内存栈(stack)中分配空间,每块空间称为帧(frame),用来保存方法内声明的变量值。
- 调用main函数时栈的变化过程如下图:
3.2 堆
- 堆(heap)是内存中另一块区域,和栈是分开的。
-
栈和堆区别是:栈按后进先出规则保存一组帧,堆则包含了大量无序的活动对象,需要通过指针来访问。
-
发送alloc消息是从堆上分配内存。
- iOS应用通过ARC来自动完成堆内存管理工作。
3.3 指针变量与对象所有权
- 如果堆内存中对象,没有指针指向它的话就会被释放掉,系统会自动记录有多少对象指针引用它,1个引用ARC就为1,2个为2,0个内存会被释放。
- NSObject实现了一个名为dealloc的方法,当某个对象即将被释放时,程序会调用该方法。
3.4 强引用与弱引用
- 只要指针变量指向了某个对象,那么相应的对象就会多一个引用计数,并且不会被释放。这种指针特性称为强引用(strong reference)。
- 也可以选择让指针变量不影响某指向对象的引用计数,这种不会改变对象拥有者个数的指针特性称为弱引用。
- 弱引用用来解决强引用循环问题(strong reference cycle,也称保留循环),当两个以上对象相互之间有强引用时就回产生强引用循环。
强引用循环问题
- 存在强引用循环问题如下图:
-
图中两个BNRItem对象中包含两个指向BNRItem对象的指针_container和_containerItem互相指向彼此。
-
当items设置为nil后,没有两个BNRItem对象引用计数减1,但是互相依然强引用,所以内存无法释放,如下图:
解决强引用问题
- 要解决上面的强引用循环问题,需要将新创建的两个BNRItem对象之间的某个指针改为弱引用。
- 大部分强引用循环可以确定一个父子关系,父对象使用具有强引用特性的指针,指向子对象。子对象使用弱引用特性指针,指回父对象。这样就可以避免强引用循环问题。
- 将上面的_container设为弱引用,如:
__weak BNRItem *_container;
,这样就解决了强引用循环问题,如下图:
3.5 属性
- 属性相当于:声明实例对象+相应存取方法。它们的等价表如下:
- 表中都具有一个实例变量
_name
和一对存取方法,右边只需要一个属性就完成了。 -
如果声明一个名为
itemName的
属性,编译器会自动生成实例变量_itemName
、取方法itemName
和存方法setItemName:
。 -
自定义属性存取方法:
- 如果覆盖了存取方法(或为只读属性覆盖了取方法),编译器就不会自动创建相应变量了,如果需要实例变量就需要明确声明。
属性的特性
- 任何属性都有一组特性,如:
@property (nonatomic, readwrite, strong) NSString *itemName;
- 多线程特性:
- 两种可选类型
nonatomic
和atomic
,通常设为nonatomic
。
- 两种可选类型
- 读/写特性:
- 两种可选类型
readwrite
和readonly
,如果时readonly
只会生成取方法。
- 两种可选类型
- 内存管理特性:
- 有4种可选类型:
strong
,weak
,copy
,unsafe_unretained
. - 对于需指向非对象属性,如:
int
,默认会选用unsafe_unretained
,不做内存管理。 - 当属性是可变子类对象(例如,NSString/NSMutableString或NSArray/NSMutableArray)指针时,应设置
copy
特性。因为可变子类有可能被其它引用者修改,所以会复制一个新的对象给属性。
- 有4种可选类型:
4 视图与视图层次结构
4.1 视图基础
- 视图是UIView对象,或是UIView子类对象。
- 视图可以处理事件,例如触摸。
- 视图会按层次结构排列,位于视图层次结构顶端的是应用窗口。
4.2 视图层次结构
- 任何一个应用都只有一个UIWindow对象,负责包含应用中所有视图,视图还可以有自己的子视图。
- 视图层次结构构成应用的界面:
- 视图会将自己绘制到layer上,然后组合起来绘制到屏幕上,每个UIView对象又一个layer属性,指向一个CALayer类对象。
4.3 创建UIView子类
- 新版本Xcode创建的项目使用ViewController管理视图,如果要实现书中画红色矩形需在
viewDidLoad
中添加如下代码:
- (void)viewDidLoad [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. CGRect firstFrame = CGRectMake(160, 240, 100, 150); BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame]; firstView.backgroundColor = [UIColor redColor]; [self.view addSubview:firstView]; CGRect secondFrame = CGRectMake(20, 30, 50, 50); BNRHypnosisView *secondView = [[BNRHypnosisView alloc] initWithFrame:secondFrame]; secondView.backgroundColor = [UIColor blueColor]; [firstView addSubview:secondView];
- 视图相关文章:
4.4 在drawRect:方法中自定义绘图
Xcode使用lldb调试:
- 与调试器共舞 - LLDB 的华尔兹
- XCODE LLDB TUTORIAL
- lldb不支持点语法,输出视图的
bounds
应输入:p (CGRect)[firstView bounds]