第六章 源文件组织

文件组织

文件组织和C++类似,.h文件为头文件,用于保存@interface指令,公共struct定义,enum常量,#defines,extern全局变量等,一般来说文件名和类名相同;.m文件为每一个.h文件对应的实现内容,包含@implementation指令、全局变量的定义、私有struct等,文件名一般与.h的文件名相同
.mm文件扩展名,意味着这是Objective-C++,可以同时使用C++和Objective-C进行编程

Xcode创建文件

File -> New -> New File然后选择Objective Class
Xcode中有群组的概念,这会使得项目更加易于浏览
注意:在每一个.m文件的头部,你都需要添加一个#import语句,包含相应的.h文件

跨文件依赖关系

可能会出现由于两个文件互相依赖,那么如果文件本身发生了变化,那么就需要重新编译文件来适应这种变化,例如CarParts-Split.m依赖于Tire.h和Engine.h文件。如果两个文件中的任何一个发生变化,都需要重新编译CarPart-Split.m文件
@class关键词的意思是告诉编译器我只会通过指针来引用它,即创建了一个前向引用,现在编译器不知道这个是什么,但是以后会知道
例如以下代码(Car.h)

那么我们只需要在Car.m内部包含Tire.h和Engine.h即可
注意:如果出现类的继承,是不能使用@class的,当且仅当类中间只出现类的引用的时候才可以用@class

第七章 深入了解Xcode

第八章 Foundation Kit介绍

常用结构体

NSRange

其中location表示起始位置,length表示范围内所含元素的个数,参考C++的substr
创建一个NSRange有多种方式
  1. 直接赋值
  2. 结构体赋值方法{…}
  3. Cocoa中提供了一个快捷函数NSMakeRange(),这个函数会返回一个NSRange,通常用来在参数中传递,比较方便

CGPoint

表示二维笛卡尔平面的一个坐标

CGSize

用来存储长度和宽度
所以在之前的Shapes的程序中可以采用一个_CGPoint和一个CGSize来表示形状,但是Cocoa中存在这个类型

CGRect

对于以上三种数据类型,Cocoa中也有创建这些数据类型的快捷函数:CGPointMake()、CGSizeMake()、CGRectMake()
C语言中结构体的性能要大于OC中对象的时间,他会消耗大量的时间

类方法

在声明时使用加号声明,表示该方法是一个类方法类似于C语言的static关键字,即不需要创建实例都可以对该方法进行调用,与之相对应的是实例方法
注意:类方法不可以调用实例方法,只能调用类方法;类方法不可以使用成员变量,但是可以使用self;类方法可以被类和对象调用

NSString

stringWithFormat函数用于创建一个NSString,这个函数的参数和NSLog的值是一样的
如下所示:
NSString的length方法可以处理Unicode字符,但是C语言的strlen不行
字符串比较函数isEqualToString,返回一个BOOL值表示两个字符串内容是否相同
注意:这里和C语言类似,不可以直接使用==运算符来比较两个字符串内容
compare函数,用于比较两个字符串字典序大小
compare: options: 方法给我们更多的选择空间,可用选项如下:
  1. NSCaseInsesitiveSearch大小写不敏感
  2. NSLiteralSearch区分大小写
  3. 比较字符串的字符个数,而不是字符串的值
我们如果要忽略大小写并按照字符个数进行排序,则需要进行如下操作:

hasPrefix hasSuffix字面意思,是否拥有某个前缀或者后缀
rangeOfString字面意思,返回这个字符串在字符串位置的NSRange,没有找到的话range.location等价于NSNotFound

NSMutableString

NSString在创建出来过后是不可以修改的(可以理解为const string),但是NSMutableString可以,需要使用

来进行类型的转换,该函数会返回一个指定大小的NSMutableString,我们可以对这个类型的变量进行操作
这三个函数是NSMutableString的一个实例方法,基本都是字面意思

NSArray

NSArray中可以存入任意类型的对象:NSString、Car、Shape、Tire或者其他想要存储的对象,甚至是其他数组或字典
注意:只能存储Objective-C的对象,不能存储原始C语言的基础数据类型,如int、float、enum、struct和NSArray中的随机指针,也不能存储对象的零值和NULL值
arrayWithObjects: 创建一个新的NSArray,并且以nil结束,例如:

NSArray *array = [NSArray arrayWithObjects:@”one”, @”two”, @”three”, nil];

也可以使用下面的方式来创建一个NSArray这个时候不必在结尾处补上nil

NSArray *array2 = @[@”one”, @”two”, @”three”];

方法- (NSUInteger) count;用于获取它所包含的对象个数
方法- (id)objectAtIndex: (NSUInteger) index;用于访问特定索引处的对象,和NSArray[1]类似
Tips:在索引大于数组中对象个数的时候,Cocoa在运行时会报NSRangeException错误
NSString中的- NSArray componentsSeparateByString: (NSString astring)方法用于将字符串切割成NSArray
NSArray中的- NSString componentsJoinedByString: (NSString astring)方法用于将NSArray中的元素合并成字符串,并用astring作为分隔符;
同样:NSArray也是不可以改变的,一般我们使用NSMutableArray类型,通过arrayWithCapacity创建一个可变数组

NSMutableArray

注意:不能通过字面量创建NSMutableArray
+ (id) arrayWithCapacity: (NSUInteger) numItems;用于可变数组的创建,长度为numItems;可以理解为C++vector的带一个unsigned参数的那个构造函数
– (void) addObject: (id) anObject;在数组末尾添加对象,相当于C++vector的push_back
– (void) removeObjectAtIndex: (NSUInteger) index;删除掉指定位置的元素,注意索引从0开始

迭代器

– (NSEnumerator *) objectEnumerator;
NSEnumerator就是迭代器
NSEnumerator的方法- (id) nextObject; 返回迭代器的下一个对象,如果不存在返回nil

快速枚举

类似这样的语法,和C++11中支持的遍历模式可以说完全相同
for(NSString *string in array)

代码块方法快速枚举

NSArray 方法- (void)enumerateObjectsUsingBlock: (void (^))(id obj, NSUInteger idx, BOOL *stop)) block;
可以并发执行,效率较高,用法如下:

NSDictionary

定义类似于C++中的map,不过多解释,和正常的一样,不可以随意添加和删除
可以使用字面量定义:@{key: value, …}
或者+ (id) dictionaryWithObjectsAndKeys: (id) firstObject, …;
该函数的参数以nil值作为结束
注意:这里面Objects在前,keys在后;字面量定义则完全相反
读取的时候可以使用NSDictionary[key]来读取value或者使用NSDictionary中的方法: – (id) objectForKey: (id) aKey;

NSMutableDictionary

可以随意添加和删除字典元素
方法+ (id) dictionaryWithCapacity: (NSUInteger) numItems;和上面差不多,创建一个大小为numItems的字典元素
方法- (void)setObject: (id)anObject forKey: (id)aKey; 字面意思,添加一个键值对,这个方法会用新的值去替换掉旧的值
方法- (void) removeObjectForKey: (id) aKey; 移除指定aKey对应的键值对
注意:同样没有适用于NSMutableDictionary的字面量初始化方法

NSNumber

由于NSDictionary中只支持对象而不支持存储基本类型数据,所以需要引入NSNumber — 一个适用于所有变量类型的一个类型
NSNumber一般用于封装基本数据类型

也可以用字面量创建对象:

此时这个就可以作为Object传入NSDictionary中了
可以使用下面的实例方法重新获取值

NSValue

NSValue是NSNumber的子类,可以封装任意值

第一个参数是指针,第二个参数是数据类型,编译器指令@encode可以直接确认数据类型。

用于提取数值,参数是这个数值的变量地址

NSNull

+ (NSNull *)null;
[NSNull null]表示这里面什么都没有,可以看作是一个Object,这个Object可以表示什么都没有这一件事情,但是nil的特殊性却保证了它不可以

查找文件实例

使用快速枚举

NSFileManager

该类允许了文件系统的交互,创建目录,删除文件,移动文件和获取文件信息等操作

第九章 内存管理

对象生命周期

对象生命周期包含诞生、生存、交友、最终死去

引用计数方法

每一个对象拥有一个与之相关联的整数,称为引用计数器。alloc、new方法或者通过copy消息创建对象时,计数器被设置为1,retain消息+1,release消息-1
即将被销毁时会发送一条dealloc消息,可以重写这个方法来释放掉已经分配的全部相关资源。可以理解为C++中的析构函数。

可以在接受其他消息的同时进行retain调用,例如[[car retain] setTire: tireAtIndex: 2]; 表示先吧car对象的计数器+1并执行setTire方法
retainCount方法,可以返回计数器的值

对象所有权

一个对象内有指向其他对象的实例变量,则称该对象拥有这些对象
我们在一个方法内部使用

以此来进行内存管理

自动释放池

给一个对象发送autorelease消息,就是将该对象添加到自动释放池中,当自动释放池被销毁时,会自动向该池中所有对象发送release消息
例如以下代码:

第一种方法在结束的时候并不会销毁对象,第二种方法在返回过后会自动销毁对象

自动释放池的创建和销毁

通过@autoreleasepool关键词或者NSAutoreleasePool对象
前者用大括号括起来,后者在创建和释放之间的代码都会使用这个自动释放池
在OSX10.4以后,可以使用drain方法来清空自动释放池而不会销毁它
说一句没有关系的:使用alloc init进行对象的创建比new要来的好 原因
注意:arrayWithCapacity方法在返回的时候会自动将NSMutableArray设置为自动释放,所以我们将可变数组作为临时变量的时候不需要手动release

ARC

垃圾回收机制无法用在IOS应用程序上,所以苹果公司建议不要在自己的代码中使用autorelease方法
在苹果公司的解决方案中有ARC(自动引用计数功能)会在编译期间自动向你的代码中插入retain
release等
但是C型的指针数组等ARC是不会参与的,例如malloc创建的字符串数组
注意:
  1. ARC不支持属性名称以new开头的命名规则
  2. 属性不能只有一个read-only而没有内存管理特性,默认的特性是assign

弱引用

弱引用不会增加引用计数
归零弱引用:在指向的对象消失的时候,这些弱引用需要被设置成nil
在声明变量的时候使用__weak关键词或者对属性使用weak特性即@property(weak)
对应的强引用也有自己的__strong关键字和strong特性。
内存管理的关键字和特性是不能同时使用的

异常处理

需要开启Xcode中的Enable Objective-C Exceptions项
@try:定义测试的代码块
@catch():参数是NSException类型,用来处理已抛出的代码块
@finally:定义无论是否有抛出异常都会执行的代码块,这段代码总会执行
@throw:抛出异常
例如:

抛出异常:

以上两种方式都可以抛出异常

异常的内存管理

处理异常的内存管理的话最好使用@try和@finally代码块,然后在finally里面处理内容
一般来讲,异常都是自动释放的,因为不知道什么时候会释放内存
但是异常内存的处理最好将Exception放在内存池之前,因为否则可能导致pool释放早于异常抛出,可能会出现问题

0 条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注