前段时间忙了一阵,终于静下心来补作业了,先把第二周的学习笔记补上。
这周主要学习的是字符串、集合这两个OC中非常重要的类型,使用自动引用计数ARC(Automatic Reference Counting)管理对象的创建和释放,以及利用协议(protocols)约定类的行为和利用类别(categories)和扩展(extensions)来定制一个类。
字符串
字符串在OC中如何处理?
一个字符串在OC中常常是字符串类(NSString)的一个实例。
而像int, float and char这样的C当中的纯量数据类型,则储存于纯量的本地变量或者属性中。
While strings of characters are usually represented as instances of the NSString class, numeric values are often stored in scalar local variables or properties.
创建字符串对象(NSString)?
可以用三种方法:
1.字面量初始化literal syntax
NSString *thirdString = @"Hello World!";
2.初始化器
NSString *firstString = [[NSString alloc] initWithCString:"HelloWorld!" encoding:NSUTF8StringEncoding];
3.工厂化方法
NSString *secondString = [NSString stringWithCString:"HelloWorld!" encoding:NSUTF8StringEncoding];
NSString和NSMutableSting?
NSMutableString是NSString的子类。他们的主要区别是:
The basic NSString class is immutable, which means its contents are set at creation and cannot later be changed. If you need to represent a different string, you must create a new string object //NSString在创建后内容就不可更改,如果要得到一个不同的字符串,我们就只能重新创建一个新的字符串对象。
The NSMutableString class is the mutable subclass of NSString, and allows you to change its character contents at runtime using methods like appendString: or appendFormat: //NSMutableString可以在创建后更改字符内容。
这一NSString的重要特性称为恒定性(immutable)。
NSString的另一个特性称为共享性:
NSString * str1 = @"Hello World!";
NSString * str4 = @"Hello World!";
//通过共享性,在实际运行时这两个字符串对象的内容会指向同一个指针。这样避免了当一个程序中具有多个"Hello World!"对象时造成的内存空间浪费。
//然而,只有通过像上述这样,字面量初始化literal syntax创建的NSString字符串才具有这一特性
NSMutableString没有共享性。
NSMutableString相比NSString还是多了很多字符串操作,像添加、删除和修改字符串。值得注意的是,在修改字符串时,如果需求,NSMutableString不是在原有内存上直接增长,而是重新分配一个更大或者更小的内存容量来存放字符。
所以一个实用的技巧是,估计好NSMutableString的capacity,预先分配好一定容量,避免以后capacity的增长:
NSMutableString *mustr3 =[NSMutableString stringWithCapacity:100]; //创建一个capacity为100的NSMutableString
集合
OC中绝大多数的集合都是对象,如数组(NSArray)、Set(NSSet)、Dictionary(NSDictionary)。
并且,集合中的元素必须是对象:
These classes are used to manage groups of objects, which means any item you wish to add to a collection must be an instance of an Objective-C class. If you need to add a scalar value, you must first create a suitable NSNumber or NSValue instance to represent it.//如果是纯量元素,我们需要首先创建一个合适的NSNumber或者NSValue实例来表达它们。
所有这些集合都支持对元素的遍历(enumeration)、查找(finding out whether a particular object is part of the collection)和访问(accessing specific items)。
所有三个集合都具有常量性(immutable):不可以更改元素长度、不可以更改元素指针、可以更改指针指向的内容。
和字符串类类似,它们对应的可变集合分别是可变数组(NSMutableArray)、可变Set(NSMutableSet)、可变Dictionary(NSMutableDictionary)。
集合的遍历有三种方法:
1.Fast Enumeration快速枚举,最快
for (<Type> <variable> in <collection>) {
...
} //Fast Enumeration
2.NSEnumeration迭代器模式,较慢
3.for循环,最慢,如果没有非用不可的情况不使用
for (<#initialization#>; <#condition#>; <#increment#>) {
<#statements#>
}
ARC
ARC(Automatic Reference Counting)自动引用计数,是OC默认的内存管理机制,针对的是堆上的对象,由编译器自动生成操作引用计数的指令(retain或release),来管理对象的创建与释放。
哪些对象受ARC管理:
OC对象指针
Block指针
使用__attribute__((NSObject))定义的typedef
哪些对象不受ARC管理:
值类型
使用其他方式分配的堆对象(如使用malloc分配)
非内存资源
自动释放池(autorelease)
对象的释放延迟到自动释放池被释放时
自动释放池Block的使用是推荐的,当其结束时,所有接受autorelease消息的对象将会被立即释放。避免对内存的琐碎管理。
APP KIT/UIKIT的事件处理,会自动使用autorelease pool,所以大多数情况无需程序员手工干预。
协议
只提供外部接口,不提供具体实现。
协议可以包含以下成员:
属性
实例方法
类方法
初始化器和析构器(不常用)
协议不可以包含:
实例变量成员
协议内成员默认具有@required属性,必须实现。
可选成员写在@optional语句之后,可以选择实现。
实现语句在具体遵循协议的类的实现中编写。
如捕鱼器类(FishTrapper)遵循捕捞协议(Trapping):
@interface FishTrapper:NSObject<Trapping> //捕鱼器类是实现类
@property NSInteger n; //实现类中需要声明协议类中的属性,因为协议自身不能合成实例变量,需要实现类在编译中合成。
@property NSMutableArray * array; //同上,这是一个实现类中声明的协议属性
@end
Trapping类只具有h文件:
@protocol Trapping //捕捞是协议类
@property NSInteger n; //捕捞类中的属性
@property NSMutableArray * array; //捕捞类中的属性
//@required
-(void)trapFishInArray:(NSMutableArray *)array withN:(NSInteger)n; //协议中的实例方法
@end
以上两个类声明的属性、方法等成员需要在实现类——捕鱼器类(FishTrapper)的implementation(m文件)中实现:
@implementation FishTrapper : NSObject
-(id)init{
...省略
}
-(void)trapFishInArray:(NSMutableArray *)array withN:(NSInteger)n{
...省略
}
@end
检查对象是否实现了协议用conformsToProtocol:
类的定制
使用类别(category)可以为类添加方法(无源代码情况)。
以NSMutableArray类为例,如果我们想让它更好地服务于我的Animal项目,给它添加一个enumerateArrayAnimal方法:
@interface NSMutableArray (AnimalEnumerateAdditions)
-(void)enumerateArrayAnimal;
@end
实现:
@implementation NSMutableArray (AnimalEnumerateAdditions)
-(void)enumerateArrayAnimal{
...省略
}
@end
各自的文件命名规则:
NSMutableArray+AnimalEnumerateAdditions.h/.m //类名+类别名.h/.m
而在编译时、有源代码情况,可以用扩展(extensions)向类添加功能,它可以被看作是匿名的类别。
扩展支持添加以下成员:
添加属性
添加实例成员
添加类方法
添加实例方法
改写属性的读写属性
由于是匿名类别,扩展的接口属性在m文件的@implementation前声明,实现代码依然在@implementation中实现。
最后作业中的错题
主要是在捕捞协议中修改动物数组时用FastEnumeration始终报错NSGenericException。
查了一下不能够在for in循环中修改所遍历的数组,无论是add或remove都不可以,如果要修改的话,可以用for(;;;)格式。