Cocoa是苹果公司为Mac OS X所创建的原生面向对象的编程环境。Cocoa包含两个Objective-C对象库,即Foundation框架和AppKit框架。Foundation框架是通用的面向对象的函数库,相当于标准库,可以在Mac OS X和iOS中使用。它提供数字和字符串,容器如数组、字典和集合,时间管理,内存管理和文件系统等等。AppKit框架包含了程序与图形用户界面交互的类和方法,基于Foundation框架建立,它只能在Mac OS X中使用。和Cocoa对应还有Cocoa Touch环境,它是为iOS所创建,包含Foundation框架和UIKit框架。UIKit框架用于iOS的图形用户界面。 本篇对Foundation框架做简要总结。 Foundation框架 、 AppKit框架 和 UIKit框架 的细节可以参考苹果的官方文档。 数字和基本数据类型不同, NSNumber 是类,它存储各种基本类型的值,可以用在需要对象的地方。可以从基本数据类型来创建 NSNumber 对象。下表给出基本数据类型和 NSNumber 对象的转换方法。
注意其中 NSInteger 、 NSUInteger 和 BOOL 类型是基本数据类型的 typedef 。 还可以使用初始化实例方法创建 NSNumber 对象, [[NSNumber alloc] initWithType:value] 。方法名称和创建和初始化类方法的名称类似,区别是前缀改为 initWith 。注意不能重新初始化已经创建的 NSNumber 对象。 有两个用于比较的方法: // 比较,相等返回NSOrderedSame,aNumber大于接收者返回NSOrderedAscending, // aNumber小于接收者返回NSOrderedDescending - (NSComparisonResult)compare:(NSNumber *)aNumber // 判断相等,相等返回YES,否则返回NO - (BOOL)isEqualToNumber:(NSNumber *)aNumber 字符串NSString 用于处理字符串对象,可以使用它创建不可变字符串,它实现为Unicode字符的数组。 NSString 对象的转换说明格式为 %@ 。 NSMutableString 对象为可变字符串,可以对字符串做删除和替换等操作。 在C字符串常量前面加上 @ 可以创建字符串常量对象,它属于 NSString 的子类 NSConstantString 。 NSString 的方法很多。 // 创建和初始化字符串,有对应的initWith版本 + (id)stringWithString:(NSString *)aString + (id)stringWithFormat:(NSString *)format, ... // 从文件创建和初始化字符串 + (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error // 从URL创建和初始化字符串 + (id)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error // 取得字符串的长度 - (NSUInteger)length // 取得字符 - (unichar)characterAtIndex:(NSUInteger)index - (void)getCharacters:(unichar *)buffer range:(NSRange)aRange // 合并字符串 - (NSString *)stringByAppendingString:(NSString *)aString - (NSString *)stringByAppendingFormat:(NSString *)format, ... // 分割字符串 - (NSString *)substringWithRange:(NSRange)aRange - (NSString *)substringFromIndex:(NSUInteger)anIndex - (NSString *)substringToIndex:(NSUInteger)anIndex // 查找子串 - (NSRange)rangeOfString:(NSString *)aString // 比较字符串 - (NSComparisonResult)compare:(NSString *)aString - (NSComparisonResult)caseInsensitiveCompare:(NSString *)aString - (BOOL)isEqualToString:(NSString *)aString // 转为小写/大写 - (NSString *)lowercaseString - (NSString *)uppercaseString // 转换为其他类型的值 - (int)intValue - (NSInteger)integerValue - (long long)longLongValue - (float)floatValue - (double)doubleValue - (BOOL)boolValue 下面是 NSMutableString 增加的一些操作。 // 创建一定大小的空的可变字符串,有对应的initWith版本 + (id)stringWithCapacity:(NSUInteger)capacity // 修改字符串:扩充、插入、删除、替换、重设 - (void)appendString:(NSString *)aString - (void)appendFormat:(NSString *)format, ... - (void)insertString:(NSString *)aString atIndex:(NSUInteger)anIndex - (void)deleteCharactersInRange:(NSRange)aRange - (void)replaceCharactersInRange:(NSRange)aRange withString:(NSString *)aString - (void)setString:(NSString *)aString Objective-C中可变数目的参数列表 ... ,使用 nil 标记这种参数列表的结束。 这里涉及了 NSRange 数据类型,它是一种结构,包含 location 和 length 成员。可以使用 NSMakeRange 函数创建它。 如果需要把字符串按转换说明进行格式转换,可以参考 NSScanner 类。 数组数组也分为可变数组和不可变数组,可变数组 NSMutableArray 是不可变数组 NSArray 的子类。数组中的元素为对象,对象可以属于不同的类。 下面是 NSArray 的一些方法。 // 创建和初始化数组,有对应的initWith版本 + (id)arrayWithArray:(NSArray *)anArray + (id)arrayWithObjects:(id)firstObj, ... // 取得数组的元素数目 - (NSUInteger)count // 查找数组中的元素 - (BOOL)containsObject:(id)anObject - (id)lastObject - (id)objectAtIndex:(NSUInteger)index - (void)getObjects:(id *)aBuffer range:(NSRange)aRange // 遍历数组 - (NSEnumerator *)objectEnumerator // 取得元素的位置 - (NSUInteger)indexOfObject:(id)anObject // 向数组中每个元素发送消息 - (void)makeObjectsPerformSelector:(SEL)aSelector // 筛选数组 - (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate // 比较数组 - (BOOL)isEqualToArray:(NSArray *)otherArray // 修改数组 - (NSArray *)arrayByAddingObject:(id)anObject // 排序 - (NSArray *)sortedArrayUsingSelector:(SEL)comparator // 使用观察器 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 下面是 NSMutableArray 增加的一些方法。 // 创建一定大小的空的可变数组,有对应的initWith版本 + (id)arrayWithCapacity:(NSUInteger)numItems // 修改数组:添加、插入、删除、替换、重设 - (void)addObject:(id)anObject - (void)insertObject:(id)anObject atIndex:(NSUInteger)index - (void)removeAllObjects - (void)removeLastObject - (void)removeObjectAtIndex:(NSUInteger)index - (void)removeObjectsInRange:(NSRange)aRange - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject - (void)setArray:(NSArray *)otherArray // 筛选数组 - (void)filterUsingPredicate:(NSPredicate *)predicate // 排序 - (void)sortUsingSelector:(SEL)comparator 可以使用快速枚举遍历数组,例: // NSArray *array,每个元素为NSString对象 for (NSString *str in array) NSLog(@"%@", str); 字典字典是键值对组成的数据集合。键和值可以是任何对象类型,但不能为 nil 。字典是无序的,它的键不可以重复。字典也包括可变字典 NSMutableDictionary 和不可变字典 NSDictionary 。 下面是 NSDictionary 的一些方法。 // 创建和初始化字典,有对应的initWith版本 + (id)dictionaryWithDictionary:(NSDictionary *)otherDictionary + (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys // 取得字典的键值对数目 - (NSUInteger)count // 比较字典 - (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary // 取得字典的键或值 - (NSArray *)allKeys - (NSArray *)allValues - (id)objectForKey:(id)aKey // 遍历字典 - (NSEnumerator *)keyEnumerator - (NSEnumerator *)objectEnumerator // 排序 - (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator 下面是 NSMutableDictionary 增加的一些方法。 // 创建一定大小的空的可变字典,有对应的initWith版本 + (id)dictionaryWithCapacity:(NSUInteger)numItems // 修改字典:重设值、删除、重设 - (void)setObject:(id)anObject forKey:(id)aKey - (void)removeAllObjects - (void)removeObjectForKey:(id)aKey - (void)removeObjectsForKeys:(NSArray *)keyArray - (void)setDictionary:(NSDictionary *)otherDictionary 可以使用快速枚举遍历字典,例: // NSDictionary *dict,键和值的类型均为NSString for (NSString *key in dict) NSLog(@"%@, %@", key, [dict objectForKey:key]); 集合集合可以看作只有键的字典,它是一组对象的集合,集合中的元素不可以重复。可以对集合进行比较,计算交集和并集。集合也有可变集合 NSMutableSet 和不可变集合 NSSet 。 下面是 NSSet 的一些方法。 // 创建和初始化集合,有对应的initWith版本 + (id)setWithSet:(NSSet *)set + (id)setWithArray:(NSArray *)array + (id)setWithObjects:(id)firstObj ... // 取得集合的元素数目 - (NSUInteger)count // 查找集合中的元素 - (NSArray *)allObjects - (id)anyObject - (BOOL)containsObject:(id)anObject // 遍历集合 - (NSEnumerator *)objectEnumerator // 向集合中每个元素发送消息 - (void)makeObjectsPerformSelector:(SEL)aSelector // 筛选集合 - (NSSet *)filteredSetUsingPredicate:(NSPredicate *)predicate // 是否子集/交集 - (BOOL)isSubsetOfSet:(NSSet *)otherSet - (BOOL)intersectsSet:(NSSet *)otherSet // 比较集合 - (BOOL)isEqualToSet:(NSSet *)otherSet // 排序 - (NSArray *)sortedArrayUsingDescriptors:(NSArray *)sortDescriptors // 使用观察器 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 下面是 NSMutableSet 增加的一些方法。 // 创建一定大小的空的可变集合,有对应的initWith版本 + (id)setWithCapacity:(NSUInteger)numItems // 修改集合:添加、删除、重设 - (void)addObject:(id)object - (void)removeObject:(id)object - (void)removeAllObjects - (void)setSet:(NSSet *)otherSet // 筛选集合 - (void)filterUsingPredicate:(NSPredicate *)predicate - (void)unionSet:(NSSet *)otherSet - (void)minusSet:(NSSet *)otherSet - (void)intersectSet:(NSSet *)otherSet // 并集/交集/差集 - (void)unionSet:(NSSet *)otherSet - (void)intersectSet:(NSSet *)otherSet - (void)minusSet:(NSSet *)otherSet 可以使用快速枚举遍历集合,用法和遍历数组类似。 文件可以通过 NSFileManager 类对文件或目录执行基本操作。下面的大部分操作有对应的 URL 版本。 // 创建文件管理器 + (NSFileManager *)defaultManager // 查看目录 - (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error - (NSDirectoryEnumerator *)enumeratorAtPath:(NSString *)path // 创建/删除项 - (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error - (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)contents attributes:(NSDictionary *)attributes - (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error // 复制/移动项 - (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error - (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error // 创建符号链接和硬链接 - (BOOL)createSymbolicLinkAtPath:(NSString *)path withDestinationPath:(NSString *)destPath error:(NSError **)error - (BOOL)linkItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error - (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path error:(NSError **)error // 检测文件 - (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory // 取得/设置属性 - (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error - (BOOL)setAttributes:(NSDictionary *)attributes ofItemAtPath:(NSString *)path error:(NSError **)error // 取得/比较文件内容 - (NSData *)contentsAtPath:(NSString *)path - (BOOL)contentsEqualAtPath:(NSString *)path1 andPath:(NSString *)path2 // 将文件路径转换为字符串 - (const char *)fileSystemRepresentationWithPath:(NSString *)path - (NSString *)stringWithFileSystemRepresentation:(const char *)string length:(NSUInteger)len // 取得/更改当前目录 - (NSString *)currentDirectoryPath - (BOOL)changeCurrentDirectoryPath:(NSString *)path 这里涉及到了 NSData 类,它可以用来设置缓冲区。它是不可变的,对应的有可变的 NSMutableData 。 下面是一些 NSData 类的方法。 // 创建和初始化缓冲区,有对应的initWith版本 + (id)dataWithBytes:(const void *)bytes length:(NSUInteger)length + (id)dataWithContentsOfFile:(NSString *)path + (id)dataWithContentsOfURL:(NSURL *)aURL + (id)dataWithData:(NSData *)aData // 取得数据 - (const void *)bytes - (void)getBytes:(void *)buffer length:(NSUInteger)length - (void)getBytes:(void *)buffer range:(NSRange)range // 取得长度 - (NSUInteger)length // 比较数据 - (BOOL)isEqualToData:(NSData *)otherData // 存储数据 - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag - (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr - (BOOL)writeToURL:(NSURL *)aURL atomically:(BOOL)atomically - (BOOL)writeToURL:(NSURL *)aURL options:(NSDataWritingOptions)mask error:(NSError **)errorPtr 下面是 NSMutableData 增加的一些方法。 // 创建一定大小的空的/初始化为0的可变缓冲区,有对应的initWith版本 + (id)dataWithCapacity:(NSUInteger)aNumItems + (id)dataWithLength:(NSUInteger)length // 更改容量 - (void)setLength:(NSUInteger)length // 取得数据 - (void *)mutableBytes // 增加数据 - (void)appendBytes:(const void *)bytes length:(NSUInteger)length - (void)appendData:(NSData *)otherData // 修改数据:替换、重置0、重设 - (void)replaceBytesInRange:(NSRange)range withBytes:(const void *)bytes - (void)resetBytesInRange:(NSRange)range - (void)setData:(NSData *)aData 还有一些用于文件路径管理的全局函数。 // 返回当前用户的登录名/全名 NSString *NSUserName(void); NSString *NSFullUserName(void); // 返回用户的主目录 NSString *NSHomeDirectory(void); NSString *NSHomeDirectoryForUser(NSString *userName); // 返回临时文件目录 NSString *NSTemporaryDirectory(void); NSString 类也包含一些用于路径和URL处理的方法。 文件的读写使用 NSFileHandle 类的方法来完成。 // 打开文件准备读取/写入/更新 + (id)fileHandleForReadingAtPath:(NSString *)path + (id)fileHandleForWritingAtPath:(NSString *)path + (id)fileHandleForUpdatingAtPath:(NSString *)path // 打开标准输入/标准输出/标准错误/空设备 + (id)fileHandleWithStandardInput + (id)fileHandleWithStandardOutput + (id)fileHandleWithStandardError + (id)fileHandleWithNullDevice // 初始化文件处理对象 - (id)initWithFileDescriptor:(int)fileDescriptor // 返回文件描述符 - (int)fileDescriptor // 读写数据 - (NSData *)availableData - (NSData *)readDataToEndOfFile - (NSData *)readDataOfLength:(NSUInteger)length - (void)writeData:(NSData *)data // 文件定位 - (unsigned long long)offsetInFile - (unsigned long long)seekToEndOfFile - (void)seekToFileOffset:(unsigned long long)offset // 扩展或截断文件 - (void)truncateFileAtOffset:(unsigned long long)offset // 同步文件 - (void)synchronizeFile // 关闭文件 - (void)closeFile 内存管理Foundation框架使用自动释放池 NSAutoreleasePool 来负责释放分配的内存,对象包含引用计数,自动释放池释放引用计数为0的对象。因此对内存的管理的主要工作就是将对象加入到自动释放池和管理对象的引用计数。 使用 alloc 方法为对象手动分配内存,对应地 dealloc 方法释放分配的内存。 retain 方法将对象的引用计数加1, release 将对象的引用计数减1。NSAutoreleasePool 的 drain 方法会向池中的每个对象发送 release 消息并发送 dealloc 消息释放引用计数为0的对象。 对于使用 alloc 方法手动分配内存的对象,可以使用 autorelease 方法将对象加入自动释放池, autorelease 方法本身不改变引用计数,而是记在池中,在池释放时发送 release 消息。而对于使用隐式分配内存的方法创建的对象,已经被加入到自动释放池中。 例: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; C *c1 = [[[C alloc] init] autorelease]; C *c2 = [c1 retain]; // ... [c2 release]; [pool drain]; Objective-C中对象的赋值是按引用传递的,因此上例中赋值后 c1 和 c2 指向同一个实例。为防止 c1 被释放导致 c2 无法访问,可以使用 retain 方法增加引用计数。 Objective-C 2.0还提供了垃圾回收机制,由系统负责跟踪管理对象的引用计数。启用垃圾回收之后,程序中的 retain 、 release 、 autorelease 和 dealloc 方法的调用会被忽略。 复制前面提到Objective-C中对象的赋值是按引用传递的,Foundation框架中给出了 copy 和 mutableCopy 方法来创建对象的副本,它们分别在 NSCopying 和 NSMutableCopying 协议中,两者的区别是前者产生不可变副本,后者产生可变副本。 copy 和 mutableCopy 方法执行的是浅复制,也就是复制对象,但对象中包含的对象则复制引用,如容器中的元素。 可以实现 NSCopying 协议来给自定义的类增加 copy 方法。类似地,也可以实现 NSMutableCopying 协议的 mutableCopy 方法来复制产生可变副本。 例: @interface Frac : NSObject <NSCopying> // ... @end - (id)copyWithZone:(NSZone *)zone { Frac *f = [[[self class] allocWithZone:zone] init]; [f setTo:a over:b]; // 复制实例变量 return f; } allocWithZone: 方法分配内存,参数 zone 和不同的存储区相关。 对于存储器方法,可以在变量声明时指定属性。 例: @property (nonatomic, copy) NSString *name; // 生成一个合并方法,类似于: - (void)setName:(NSString *aName) { if (aName != name) { [name release]; name = [aName copy]; } } 这里为 name 指定了 copy 属性和 nonatomic 属性。 nonatomic 属性告诉系统不使用互斥锁来保护实例变量, atomic 是默认的属性,对于单线程中运行的代码可以使用 nonatomic 属性来提升性能。 归档可以通过XML格式的属性列表来归档 NSString 、 NSArray 、 NSDictionary 和 NSData 。使用 writeToFile:atomically: 方法可以将数据以一定格式写入到XML文件中,相反地使用 ...WithContentsOfFile: 方法读出数据。从字典创建属性列表时,键必须是 NSString 对象。 属性列表对对象的类型有一定的限制,可以使用 NSKeyedArchiver 将不限类型的对象或嵌套对象进行归档,对归档数据或文件对应的使用 NSKeyedUnarchiver 进行解档。 // NSKeyedArchiver // 归档到可变缓冲区 - (id)initForWritingWithMutableData:(NSMutableData *)data // 归档到数据/文件 + (NSData *)archivedDataWithRootObject:(id)rootObject + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path // NSKeyedUnarchiver // 从缓冲区解档 - (id)initForReadingWithData:(NSData *)data // 从数据/文件解档 + (id)unarchiveObjectWithData:(NSData *)data + (id)unarchiveObjectWithFile:(NSString *)path 归档到数据也提供了一种对象深复制的办法。 使用 NSKeyedArchiver 不能直接对自定义类型的对象进行归档,需要实现 NSCoding 协议。 // 编码 - (void)encodeWithCoder:(NSCoder *)encoder // 解码 - (id)initWithCoder:(NSCoder *)decoder 使用 NSCoder 类中的方法添加编码和解码的规则。 // 编码/解码Objective-C的类 - (void)encodeObject:(id)objv forKey:(NSString *)key - (id)decodeObjectForKey:(NSString *)key 对基本数据类型和 NSInteger 类型,可以使用下表中的方法。
例: @interface A : NSObject <NSCoding> { int i; float f; NSString *s; } @property int i; @property float f; @property (nonatomic, copy) NSString *s; @end @implementation A @synthesize i, f, s; - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:i forKey:@"A.i"]; [encoder encodeObject:f forKey:@"A.f"]; [encoder encodeObject:s forKey:@"A.s"]; } - (id)initWithCoder:(NSCoder *)decoder { i = [decoder decodeIntForKey:@"A.i"]; f = [decoder decodeFloatForKey:@"A.f"]; s = [[decoder decodeObjectForKey:@"A.s"] retain]; return self; } @end // 归档示例 A *a1 = [[A alloc] init], *a2; a1.i = 10; a1.f = 1.5; a1.s = @"a string"; [NSKeyedArchiver archiveRootObject:a1 toFile:@"a.archive"]; a2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"a.archive"]; [a1 release]; |
|