Objective-C基础知识点(下)
//只要在类别中声明一个方法,编译器就会表示:"好了,该方法已经存在,如果遇到编程人员使用该方法,我不会提出警告";
//假设Car类有一个名为rotateTires的方法,我们可以用另外一个名为moveTireFromPosition:toPosition:的方法来实现rotateTire方法;第二个是实现细节,而不是将其放在Car类的公共接口;通过类别声明moveTireFromPosition:toPosition:方法,rotateTire方法可以使用它,但不会引发编译器产生警告;
//创建一个NSObject的类别称为”创建一个非正式协议”,非正式协议只是一种表达方式,它表示"这里有一些你可能希望实现的方法,你可以使用它们更好地完成工作”;使用非正式协议,你可以只实现你想要的方法;
//委托强调类别的另一种应用:被发送给委托对象的方法可以声明为一个NSObject的类别;唯一条件:只要对象实现了委托方法,任何类的对象都可以成为委托的对象;
eg:[browser setDelegate:finder]; —>相当于”继承”了browser类对象的方法,实现了C++中多继承的特性;
//利用类别可以声明非正式协议;非正式协议是NSObject的一个类别,它列出了对象可以响应的方法;非正式协议用于委托,委托是一种允许你轻松定制对象行为的技术;
//实现<NSCopying>协议方法:
1 -(id)copyWithZone:(NSZone*)zone 2 { 3 myClass*classCopy=[[[self class]allocWithZone:zone]init]; 4 // & additional instance variable copy 5 return classCopy; 6 }
//正式协议的可选方法特性跟非正式协议的效果一样,但正式协议的好处是:可以用来在类声明和方法声明中明确表达我们的意图; 因此,非正式协议逐渐被替换成了带有@optional方法的正式协议;
//代码块声明:<returntype>(^blockname)(list of arguments)=^(argument){body;};
//typedef定义了一个名称为MKSampleMultiply2BlockRef的代码块变量:
1 typedef double(^MKSampleMultiply2BlockRef)(double c,double d); 2 MKSampleMultiply2BlockRef multiply2=^(double c,double d){return c*d}; 3 printf(“%f,%f”,multiply2(4,5),multiply2(5,2)};
//代码块是对象,可以使用Block_release()和Block_copy函数适当管理内存;
//利用并发性最基础的方法是使用POSIX线程来处理程序的不同部分使其能够独立执行;POSIX线程拥有支持C语言和Objective-C的API;因为线程是级别较低的API,你必须手动管理;
//为了减轻在多核上编程的负担,苹果公司引入了GCD;如果想使用GCD,你需要提交代码块或函数作为线程来运行;
//如果你定义了一个属性并且没有指定关键字nonatomic,编译器会生成强制彼此互斥的getter和setter方法;如果你不在意,或者知道这些属性不会被多个线程访问的话,可以添加nonatomic关键字;
//atomic是一种线程保护技术,防止在写操作还未完成时被另外一个线程读操作,造成数据错误;
//NSObject提供了简单方法performSelectorInBackground:withObject:创建一个线程在后台执行;
//GCD可以使用调度队列,它与线程很相似但使用起来更简单;只需写下你的代码,并把它指派为一个队列,系统就会执行它了;
//①连续队列:有时有一连串任务需要按照一定的顺序执行,这时便可以使用连续队列;任务执行的顺序为先入先出(FIFO):只要任务是异步提交的,队列就会按照预定顺序执行;
//②并发队列也遵循FIFO规范,且任务可以在前一个任务结束前就开始执行;一次运行的任务数量是无法预测的;
//③主队列:使用dispatch_get_main_queue可以访问与应用程序主线程相关的连续队列;因为这个队列跟主线程相关,所以必须小心安排这个队列中的任务顺序,否则会阻塞主应用程序运行;
//④当前队列:使用dispatch_get_current_queue来找到当前运行的队列代码块;如果在代码块对象之外调用了这个函数,则它会返回主队列;
//队列是引用计数对象,可以使用dispatch_retain()和dispatch_release()来管理其内存;
//队列的层级非常低,因此Objective-C提供些被称为操作(operation)的API(NSInvocationOperation,NSBlockOperation,NSOperationQueue);如果想要使用操作,首先需要创建一个operation对象,然后将其指派给操作队列,并让队列执行它;
//在Cocoa中,有一类名为属性列表的对象,简写为plist;这些列表用来放置一些Cocoa能够处理(主要是存储到文件和从文件中加载)的对象;这些属性列表类是NSArray、NSDictionary、NSString、NSNumber、NSDate、NSData以及它们的可修改形态;
//Cocoa提供了属性列表以及对象编码来加载和保存文件;
//如果对象集合中的对象类型全部为属性列表,可以使用便捷的函数(-writeToFile:atomically:用于将属性列表的内容写入文件),将它们在磁盘中存取;
//你无法总是把对象信息表示为属性列表类,Cocoa具备一种将对象转换成某种格式并保存到磁盘中的机制(编码与解码),并且能够基于保存的数据创建新对象;
//如果你拥有自己的对象,而这些对象又不是属性列表类型,可以采用NSCoding协议和实现方法来编码和解码对象:将大量对象转换成NSData,然后保存到磁盘中供以后读取;
//通过直接调用方法、属性的点表示法或设置实例变量来直接更改对象状态;而键/值编码(KVC:key-value coding)是一种间接更改对象状态的方式,其实现方法是使用字符串表示要更改的对象状态;
//[myObject valueForKey:@“key"]会先查找以参数命名的getter方法(-key/-isKey),如果没有,会在对象内寻找命名格式为_key/key的实例变量;
//通过-valueForKey使用元数据(描述数据的数据,对数据及信息资源的描述性信息)打开对象并进入其中查找需要的信息,即使没有getter方法也能获取对象值,不需要通过对象指针来直接访问实例变量;
//对于KVC,Cocoa会自动装箱和开箱标量值;自动将标量值(int、float、struct)放入NSNumber和NSValue中;
//出了通过键设置值之外,键/值还支持指定键路径,就像文件系统一样,你可以遵循一系列关系来指定该路径;这些键路径的深度是任意的,具体取决于对象图的复杂度,可以使用诸如”car.interior.airconditioner.fan.velocity"这样的键路径;
//如果键路径中含有一个数组属性,则该键路径的其余部分将被发送给数组中的每个对象,即查询响应数组中的每个对象,然后将查询结果打包到另外一个数组中并返回给你;
eg:NSArray*pressures=[car valueForKeyPath:@“tires.pressure”]
//键路径还可以用来快速运算:
NSNumber*sum=[garage valueForKeyPath:@“cars.@sum.mileage”];
@sum获取左侧指定的集合,对集合中的每个对象使用右侧的键路径,然后将结果转换成一个集合;
//不要滥用KVC:①KVC需要时间来解析字符串来计算你需要的答案,因此速度比较慢; ②编译器不能判断键路径是否错误;
//KVC机制的dictionaryWithValuesForKeys:方法接受一个字符串数组作为键在类对象中查找相应的值,然后构建一个字典;我们还可以通过setValuesForKeyWithDictionary:方法更改那些值;
//不存在值为nil的键,但存在值为[NSNull null]的键;
//假设我们需要修改一个对象,但想确保在修改它时没有其他对象可以访问它:@synchronized(object)
//Cocoa提供了一个名为NSPredicate的类,它用于指定过滤器的条件;Cocoa用NSPredicate描述查询的方式,原理类似于在数据库中进行查询;可以在数据库风格的API中使用NSPredicate类,比如Core Data和Spotlight;
//两种基本方式创建NSPredicate对象:①创建多个对象,并将它们组合起来;这需要大量代码,如果你正在构建通用用户界面来指定查询,采用这种方式比较简单; ②查询代码中的字符串:NSPredicate*predicate=[NSPredicate predicateWithFormat:@“%k==%@“,@“name”,@“herbie”];
//数组过滤器:数组的类别方法-filteredArrayUsingPredicate:和-filterUsingPredicate;
//灵活的、非硬编码的谓词:
1 NSPredicate*predicateTemplate=[NSPredicate predicateWithFormat:@"engine.horsepower>$POWER"]; 2 NSDictionary*varDict=[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:150],@"POWER",nil]; 3 NSPredicate*predicate=[predicateTemplate predicateWithSubstitutionVariables:varDict]; 4 //创建了一个谓词,条件是引擎功率要大于150
//使用为谓词得到两个数组的交集:(对于将谓词用于简单的值,而非那些可以通过键路径进行操作的复杂对象,用SELF就足够了)
1 NSArray*names1=[NSArray arrayWithObjects:@"Herbie",@"Nana"@"YingZ"@"Elvis",nil]; 2 NSArray*names2=[NSArray arrayWithObjects:@"Haili",@"Nana"@"YingZ"@"Leversi",nil]; 3 4 NSPredicate*predicate=[NSPredicate predicateWithFormat:@"SELF IN %@",names1]; 5 results=[names2 filteredArrayUsingPredicate:predicate]; 6 NSLog(@"%@",results); 7 //结果为(Nana,YingZ)