• 1. 分享人:李航(酷酷) http://weibo.com/lidaohang欢迎大家参与"爱疯了"技术交流分享
  • 2. 21.Objective-C简介 欢迎来到Objective-C的领地! 本文将介绍Objective-C的历史,以及相关特性和概要简介。 1983年,Objective-C诞生了。 1985年,Next公司使用Objective-C开发出了nextstep操作系统 1997年,apple收购了Next公司,在nextstep基础上,开始设计Mac OS。 2001年,apple正式发布Mac OS X 2007年,apple发布iphone.................. Objective-C: 一种面向对象的语言标准c语言的一个超集,使用的是smalltalk风格单继承,每个类最多只有一个父类动态运行,大部分都是工作时才知道 Objective-C不同于C++: 不支持操作符重载,模版和多重继承。
  • 3. 32.Objective-C与C++ 每个Objective-C对象都隐藏着一个数据结构,它的第一个成员变量或者说实例变量是"isa"指针。 isa指针指向的是对象的类,这个类也是一个对象,有自己的权限,是根据类的定义编译而来的。类对象负责维护一个方法调度表,该表实际上是由指向类方法的指针组成的。类对象中还保留一个超类的指针,该指针又有自己的方法调度表和超类。 isa指针对消息分发机制和cocoa对象的动态能力很重要。 C++ 与Objective-C最大的区别在于分配方法的机制不同,C++ 是基于虚拟表机制确定虚函数调用什么代码,而Objective-C 使用运行时,函数进入各种类结构中查找相应的代码以供调用。这么一比,很明显 C++ 的效率要高的多,正因如此,我们要明确的是,Objective-C 牺牲了一定的速度和安全,换来了灵活和便捷,这是一种权衡利弊的做法。
  • 4. 43. 常见语法说明 1.头文件引用使用 #import “ 文件名”或者 #import < 文件名>的形式以确保每个头文件仅被包含一次 。 2.类声明以 @interface类名:继承类 开头,以 @end 结尾,类实现以 @implementation类名 开头,以 @end 结尾。 3.实例方法,即成员方法,在方法名前面添加一个减号(-);类方法,在方法名前面添加一个加号 (+) 。 4.类方法的调用格式为 [类名 类方法],成员方法调用格式为 [实例名 实例方法],这种模式在ObjC 中被称为消息机制,[ 对象 消息]即给对象发送了一个消息,产生的效果就是该对象调用了该类中定义的对应的实例方法 。 5.类属性: NSString *aString; 6.协议 @protocol IQuery -(void) Query:(NSString*) sql; @end
  • 5. 5头文件: #import @interface MemFoo: NSObject { //属性 int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str; //重载NSObject类初始化方法 @end
  • 6. 6实现类: @implementation MemFoo @synthesize x; @synthesize name; //重载的实现 -(MemFoo*)init:(int)n:(NSString*)str { self=[super init]; //先使用父类方法进行初始化 if (self!=NULL) { self.x=n; self.name=str; } return self; } @end 调用该类: int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; MemFoo* myMem=[[MemFoo alloc]init:5:@"hello"]; [myMem release]; }
  • 7. 74.属性的介绍与使用: @property 类型 名字 属性主要分为三类: 1. 读写属性(readwrite/ readonly) 2. Setter属性 (assign/retain/copy) 3. 原子属性 (atomicity/nonatomic) 如果属性是对象类型,你需要使用retain,assign,copy参数,表示setter方法内部实现的时候,持有对象的方式。其中retain就是增加引用计数,强引用类型。assign就是变量的直接赋值,弱引用类型,也是默认值。copy就是把setter的参数复制一遍,再赋给成员变量。 如果你不给出持有对象的方式,编译器就会给出警告。 原子属性中,atomic是默认值,表示属性是原子的,支持多线程并发访问(在setter实现中加入了同步锁),后者是非原子的,适合在非多线程环境中提升效率,没有加入同步锁。
  • 8. 8示例代码如下: #import @interface Person :NSObject{ NSString *name; int age; } @property int age; @property (copy) NSString *name; @end 其中 name,age代码经过编译器生成如下代码: -(int) age;-(void) setAge: (int)age;-(NSString*)name;-(void)setName:(NSString*)value;
  • 9. 95.重载父类初始化方法: @interface MemFoo: NSObject { int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str; //重载NSObject类初始化方法 @end
  • 10. 10@implementation MemFoo @synthesize x; @synthesize name; //重载的实现 -(MemFoo*)init:(int)n:(NSString*)str { self=[super init]; //先使用父类方法进行初始化 if (self!=NULL) { self.x=n; self.name=str; } return self; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; MemFoo* myMem=[[MemFoo alloc]init:5:@"hello"]; [myMem autorelease]; NSLog(@"00000000 x is = %x, name is =%@ ",[myMem x],[myMem name]); [pool drain]; return 0; }
  • 11. 116.字符串类各种操作方法 NSString *str=@"every day keep up"; NSMutableString *mstr; NSRange substr; mstr=[NSMutableString stringWithString:str]; //初始化可变字符串 [mstr insertString:@"xiaxia" atIndex:[mstr length]];//在指定位置插入字符串 [mstr appendString:@"append"]; //链接新字符串 [mstr deleteCharactersInRange:NSMakeRange(1, 3)];//删除某个range的字符串 [mstr setString:@"new"]; [mstr replaceCharactersInRange:NSMakeRange(1, 2) withString:@"ame"]; //替换某个位置字符串 NSString *search=@"am"; NSString *replace=@"helleee"; substr=[mstr rangeOfString:search]; if (substr.location!=NSNotFound) { [mstr replaceCharactersInRange:substr withString:replace]; }//查找替换某些字符串 search=@"e"; replace=@"a"; substr=[mstr rangeOfString:search]; while (substr.location!=NSNotFound) { [mstr replaceCharactersInRange:substr withString:replace]; substr=[mstr rangeOfString:search]; } NSLog(@"mstr is: %@",mstr);
  • 12. 127.数字类的各种操作方法 NSNumber *myNumber, *floatNumber, *interNumber; NSInteger myInt; myNumber=NULL; interNumber=NULL; floatNumber=NULL; interNumber=[NSNumber numberWithInt:110]; //初始化整数 myInt=[interNumber integerValue]; //获取整数值 NSLog(@"myInt is %li", (long)myInt); floatNumber=[NSNumber numberWithFloat:100.00]; NSLog(@"float number is %g", [floatNumber floatValue]); myNumber=[NSNumber numberWithChar:'A']; NSLog(@"char number is %x", [myNumber charValue]); if ([interNumber isEqualToNumber:floatNumber]==TRUE) { //比较两个数 NSLog(@"HAHAHA"); }
  • 13. 138.集合类的各种操作方法 NSMutableArray *weekName=[NSMutableArray arrayWithObjects:@"MM",@"TT",@"WW",nil]; int i=0; for(i=0;i<3;i++) { NSLog(@"%i %@", i+1,[weekName objectAtIndex:i]); } NSMutableArray *MutableArray = [NSMutableArray alloc] init]; NSArray *array = [NSArray arrayWithObjects: @"a",@"b",@"c",nil]; NSLog(@"array:%@",array); MutableArray = [NSMutableArray arrayWithArray:array]; NSLog(@"MutableArray:%@",MutableArray); array1 = [NSArray arrayWithArray:array]; NSLog(@"array1:%@",array1);
  • 14. 149.文件类的各种操作方法 NSString *fName=@"testfile.m"; NSFileManager *fm=NULL; NSDictionary *dict=NULL; fm=[NSFileManager defaultManager]; if ([fm fileExistsAtPath:fName]==NO) { NSLog(@"file not exist!"); return 1; } if ([fm copyPath:fName toPath:@"newfile" handler:nil]==NO) { NSLog(@"copy failed!"); } if ([fm movePath:@"newfile" toPath:@"newfolder" handler:nil]==NO) { NSLog(@"move failed"); } if ((dict=[fm fileAttributesAtPath:@"newfolder" traverseLink:NO])==nil) { NSLog(@"get file attributes failed"); } NSLog(@"file size is %i bytes",[[dict objectForKey:NSFileSize] intValue]); if ([fm removeFileAtPath:@"newfolder" handler:nil]==YES) { NSLog(@"remove successful!"); }
  • 15. 1510.协议 正式协议(protocal) 其实就是非正式协议(interface)换了一种写法而已,看上去更正规一些,语义上更强烈一些:要求采用该协议的类,”必须”实现协议中约定的方法。但是比较娱乐的是,即使是号称正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。(当然正式协议也有它存在的意义,后面会提到) 这里我们定义一个IQuery的协议 协议: @protocol IQuery -(void) Query:(NSString*) sql; @end 头文件类: @interface DBQuery : NSObject { } @end 实现类: @implementation DBQuery -(void) Query:(NSString *)sql { NSLog(@”Query is called. sql:%@”,sql); } @end
  • 16. 1611.内存管理 移动开发的特点:资源的有限性。作为手持设备,iphone的内存与传统的PC不可同日而语,这就要求我们在开发IOS程序的过程中,首要也是最重要的任务就是解决内存释放问题,本文将在网络上搜集的关于内存管理的经验予以分享。 开发iPhone 应用程序并不难,基本上就是三个词 - “memory, memory, memory” 。iPhone OS 对内存的要求很严格,有memory leak ,杀掉; 内存使用超限额,杀掉。一个经过测试的程序,在使用过程中90%以上的崩溃都是内存问题造成的。在这里简单总结一下Objective-C 内存管理。 一、基本概念 Objective-C 的内存管理基于引用计数(Reference Count)这种非常常用的技术。简单讲,如果要使用一个对象,并希望确保在使用期间对象不被释放,需要通过函数调用来取得“所有权”,使用结束后再调用 函数释放“所有权”。“所有权”的获得和释放,对应引用计数的增加和减少,为正数时代表对象还有引用,为零时代表可以释放。
  • 17. 1711.内存管理 1、函数 获得所有权的函数包括 alloc - 创建对象是调用alloc,为对象分配内存,对象引用计数加一。 copy - 拷贝一个对象,返回新对象,引用计数加一。 retain - 引用计数加一,获得对象的所有权。 另外,名字中带有alloc, copy, retain 字串的函数也都认为会为引用计数加一。 释放所有权的函数包括 release - 引用计数减一,释放所有权。如果引用计数减到零,对象会被释放。 autorelease - 在未来某个时机释放。下面具体解释。 autorelease 在某些情况下,并不想取得所有权,又不希望对象被释放。例如在一个函数中生成了一个新对象并返回,函数本身并不希望取得所有权,因为取得后再没有机 会释放(除非创造出新的调用规则,而调用规则是一切混乱的开始),又不可能在函数内释放,可以借助autorelease 。所谓autorelease , 可以理解为把所有权交给一个外在的系统(这个系统实际上叫autorelease pool),由它来管理该对象的释放。通常认为交给 autorelease 的对象在当前event loop 中都是有效的。也可以自己创建NSAutoreleasePool 来控制autorelease的过程。 据苹果的人说,autorelease效率不高,所以能自己release的地方,尽量自己release,不要随便交给autorelease来处理。
  • 18. 1811.内存管理 2、规则 引用计数系统有自己的引用规则,遵守规则就可以少出错: 获得所有权的函数要和释放所有权的函数一一对应。 保证只有带alloc, copy, retain 字串的函数才会让调用者获得所有权,也就是引用计数加一。 在对象的 dealloc函数中释放对象所拥有的实例变量。 永远不要直接调用dealloc来释放对象,完全依赖引用计数来完成对象的释放。 有很多类都提供“便利构造函数(convenience constructors)”,它们创建对象但并不增加引用计数,意味着不需要调用release来释放所有权。很好辨认,它们的名字中不会有alloc和copy。 只要遵守这些规则,基本上可以消除所有Intrument可以发现的内存泄露问题。 3、容器 类似NSArray, NSDictionary, NSSet 等类,会在对象加入后引用计数加一获得所有权,在对象被移除或者整个容器对象被释放的时候释放容器内对象的所有权。类似的情况还有UIView对 subview的所有权关系,UINavigationController对其栈上的controller的所有权关系等等。 4、深拷贝和浅拷贝 copy: 建立一个索引计数为1的对象,然后释放旧对象 retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 也就是说,retain是指针拷贝,copy是内容拷贝。
  • 19. 1911.内存管理 内存管理算是学习一门语言时,比较难但是最重要的一部分。 object-c 中的Foundation框架带入了引用计数这一概念和思想来管理内存。极大的减轻了程序员内存管理的负担,你不必再那么小心翼翼。 引用计数的概念如下,创建对象时,将它的引用计数设置为1,每次必须保持该对象时,就发送一条retain消息,使其引用计数加1。Foundation框架提供的其他一些方法也可以增加对象的引用计数,例如,把对象添加到数组中。 不需要对象时,可以通过发送一条release消息,使对象的引用计数减1。 当对象的引用计数到0时,系统就知道不再需要这个对象了,因此系统会释放(deallocates)它的内存。这是通过一条dealloc 消息而实现的。 首先,我们看下面的代码示例:
  • 20. 2011.内存管理 NSString *str0=@"str0"; NSString *str1=[NSString stringWithString:@"str1"]; NSMutableString *str2=[NSMutableString stringWithString:@"str2"]; NSMutableArray *strArray=[NSMutableArray array]; NSLog(@"%x, %x, %x", [str0 retainCount],[str1 retainCount],[str2 retainCount]); [strArray addObject:str0]; [strArray addObject:str1]; [strArray addObject:str2]; NSLog(@"%x, %x, %x", [str0 retainCount],[str1 retainCount],[str2 retainCount]); [str0 retain]; [str1 retain]; [str2 retain]; NSLog(@"%x, %x, %x", [str0 retainCount],[str1 retainCount],[str2 retainCount]); [str2 release]; //因为retain了,必须要release一次 运行结果如下: 2011-03-22 01:20:25.806 MemoryTest[486:a0f] ffffffff, ffffffff, 1 2011-03-22 01:20:25.808 MemoryTest[486:a0f] ffffffff, ffffffff, 2 2011-03-22 01:20:25.809 MemoryTest[486:a0f] ffffffff, ffffffff, 3 内存中常量字符串的空间分配与其他对象不同。他们没有引用计数机制,因为不会去释放这些对象。这也解释了为啥retaincount为ffffffff,最大的无符号整数。或者UINT_MAX. 可变字符串对象str2被设置为常量字符串@"str2"的副本。通过发送stringWithstring消息来实现。
  • 21. 2111.内存管理 自动释放池,在Objective-C模块中,发挥着重要作用,能够帮助我们清理很多内存。但是它也不是万能的,也必须要合理小心的使用。 本文通过一个示例代码,来介绍下自动释放池的用法和注意事项。 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; MemFoo *pMem=[[MemFoo alloc]init]; NSLog(@"aaaaa retaincount: %d", [pMem retainCount]); [pool drain]; pool=[[NSAutoreleasePool alloc]init]; [pMem autorelease]; //不会增加引用计数 NSLog(@"bbbbb retaincount: %d",[pMem retainCount]); [pMem retain]; NSLog(@"ccccc retaincount: %d",[pMem retainCount]); [pool drain]; NSLog(@"ddddd retaincount: %d",[pMem retainCount]); [pMem release]; //必须要自己主动释放一次 运行结果如下所示: 2011-03-22 23:39:18.185 MemoryTest[478:a0f] aaaaa retaincount: 1 2011-03-22 23:39:18.187 MemoryTest[478:a0f] bbbbb retaincount: 1 2011-03-22 23:39:18.188 MemoryTest[478:a0f] ccccc retaincount: 2 2011-03-22 23:39:18.188 MemoryTest[478:a0f] ddddd retaincount: 1 所以,除了依赖于自动释放池外,对于额外的增加引用,必须由自己去亲自释放。
  • 22. 2212.总结: 与C语言相比要注意的地方: 1. 文件介绍:Objective-C 也使用头文件(header files),后缀为 .h, 但使用 .m(即 message, 其他面向对象编程语言也叫 method),作为源文件的后缀。 在Objective-C中使用#import<>,而不使用#include<>,#import可以保证头文件只被包含一次。 2. 与C一致的地方: 数据类型,表达式,各种运算符 循环:for, while, do while, break, continue 分支:if, else, switch 3. NSlog()函数:与printf()类似,想控制台输出信息。但它增加了一些特性,如时间戳等。 【cocoa对起所有的函数,常量和类型名称都添加了NS前缀。】 4. 双引号的前面的@表示这双引号中的字符串应该作为cocoa的NSString元素来处理。 5. 布尔类型BOOL:值为YES,NO; 6. %d表示输出整数 %@表示输出NSString类型 %s表示输出字符串数组(char*); 7. objective-c中的方括号: 1. 用于通知某个对象该做什么。 2. 方括号内第一项是对象,其余部分是你需要对象执行的操作。 3. 在objective-c中通知对象执行某种操作,称为发送消息。(也叫调用方法) 8. 标识符id:是一种泛型,用于表示任何种类的对象。
  • 23. 2312.总结: 9. 类声明@interface: @interface Circle:NSObject //为Circle类定义接口;NSObject表示是父类。 {//以下是数据成员 ShapeColor fillColor; ShapeRect bounds; } //以下是方法声明 -(void) setFillColor: (ShapeColor) fillColor; //前面的短线表明这是方法声明 //短线后面是方法的返回类型 //接着是方法名 //冒号后面是参数,其中(ShapeColor)是参数类型, fillColor是参数名 -(void) setBounds:(ShapeRect) bounds; -(void) draw; //减号就是普通函数 //加号就是静态函数 @end //结束声明 objective-c看到@符号,就把它看成是C语言的扩展。 一个类的完整声明如下: @interface CClassA(Category): CBaseClass //类名(类别名):父类<协议>
  • 24. 24总结: 1.Foundation kit: Cocoa是由两部分框架组成的:foundation kit [包括一些基础类]和 application kit.【包括用户接口对象和高级类】 创建字符串: NSString *test; test=[NSString stringWithFormat:@"i'm %d years old!",23]; 若在声明方法时在方法前面添加了加号,那就表示把这个方法定义为类方法【这个方法属于类对象,而不是类的实例对象。】 NSArray类:可以存放任意类型的对象. 它有两个限制: 1. 它只能存储objective-c的对象,但不能存储C中的基本数据类型,如int , float, enum, struct等。 2.不能存储nil(对象的零值或NULL值);【因为在创建NSArray时,要在列表结尾添加nil代表列表结束。】 创建NSArray: NSArray *array; array=[NSArray arrayWithObjects:@"one",@"two",nil]; NSString, NSMutableString类; 【NSString是不可变的,即一旦创建完成,就不能通过删除字符或添加字符的方式来改变它;
  • 25. 25总结: 而NSMutableString是可变的。 这两个类就像JAVA中的string与stringBuffer类的区别。】 NSArray, NSMutableArray类; NSEnumerator枚举; 【 NSEnumerator *emun; Emun=[array objectEnumerator]; Id thingie; While(thingie=[enumerator nextObject]){} 】 NSDictionary:字典(关键字及其定义的集合。)【也成为散列表,关联数组】,NSMutableDictionary类; NSNumber:用来包装基本数据类型,如int ,char, float, bool;【将一个基本类型的数据包装成对象叫做装箱。】 NSValue:它可以包装任何类,NSNumber是它的子类。 NSNull: 在cocoa中看到“CF”字样时,就表示它是苹果公司的Core Foundation 框架相关的内容。 NSAutoreleasePool:自动释放内存池。
  • 26. 26总结: 2.内存管理 每个对象都有一个与之关联的引用计数(也叫保留计数) 当使用alloc, new 方法或通过 copy消息(生成接收对象的一个副本)创建一个对象时,对象的引用计数值被设为1; 给对象发retain消息时,增加该值; 发送release消息时,减少该值; 当一个对象的引用计数值变为0时,objective-c会自动向对象发送一条dealloc消息。销毁该对象。 你可以在自己的对象中重写该方法, 使用retainCount消息,可以获取引用计数器的值。 -(id) retain; -(void) release; -(unsigned) retainCount; 自动释放池:autorelease pool; 创建: NSAutoreleasePool *pool; pool=[[NSAutoreleasePool alloc] init]; 销毁: [pool release]; 注意:xcode自动生成的代码,销毁pool池时,使用的是[pool drain],drain方法只是清空释放池,但不销毁pool.所以在自己编写代码时还是使用release. 而且,drain只适用于MAC OS 10.4以上的版本,而release适用于所有版本。 只有在向某个对象发送autorelease消息时,该对象才会添加到NSAutoreleasepool中,才会被自动释放。 如:[car autorelease];
  • 27. 27总结: 内存管理黄金准则: 只有通过alloc, new和 copy方法创建的对象,才需要程序员负责向该对象发送release或autorelease消息。 而通过其他方法获得的对象,则默认为已经被设置为自动释放,所以不需要程序员做任何操作了。 在objective-c 2.0中有垃圾回收机制, 如果要对某个项目使用垃圾回收: 项目信息--build选项卡--查询"garb",出现“objective-c Garbage Collection”,将其值设置为“required[-fobjc-gc-only]” 启用垃圾回收后,通常的内存管理命令全都变成了空操作指令,不执行任何操作。 开发iphone软件,不能使用垃圾回收。 对象初始化 两种创建新对象的方法: [类名 new] [[类名 alloc] init] 这两种方法是等价的,但cocoa的惯例是使用后者。 alloc在为对象分配空间的同时,将这块内存初始化为0; Init方法:初始化实例变量,使对象处于可用状态。[返回类型为id, 返回的值描述了被初始化的对象] 使用new创建新对象时,系统要完成两个步骤: 1. 为对象分配内存,即对象获得一个用来存放其实例变量的内存块; 2. 自动调用init方法,让该对象处于可用状态。
  • 28. 28总结: 3.类别: 类别(category)是一种为现有的类添加新方法的方式。类别的声明: @interface NSString (NumberConvenience) //类名 (类别名) -(NSNumber) lengthAsNumber; //扩充方法声明 @end 使用时使用原来的类名,就可以调用他的所有类别中的方法。 类别的局限性: 1. 不能向类中添加新的实例变量; 2. 在类别中的方法若与类中现有的方法重名,则类中的方法不可用,被类别中的新方法取代。 类别的作用: 1. 将类的实现分散到多个文件或框架中; 2. 创建对私有方法的前向引用; 【Cocoa中没有真正的私有方法,则实现私有方法类似功能的方法为: 先在类别中声明方法;然后到现有类的实现中实现该方法。 这样这个类中的其他方法可以使用该方法,而其他外部的类就不会知道该方法的存在了。】 3. 向对象添加非正式协议。 【创建一个NSObject的类别称为创建一个非正式协议。】 委托delegate是一种对象,另一个类的对象会要求委托对象执行它的某些操作。 受委托对象在某个时间(某个事件触发)时,会自动通知委托对象执行委托方法。 选择器:@selector():选择器只是一个方法名称,但它以objective-c运行时使用的特殊方式编码,以快速执行查询。圆括号中的内容是方法名。 所以Car类的setEngine:方法的选择器是:@selector(setEngine: 受委托对象如何知道其委托对象是否能处理它(受委托对象)发送给它(委托对象)的消息? 通过选择器,受委托对象先检查委托对象,询问其是否能响应该选择器。如果能,则向它发送消息。
  • 29. 29总结: 3.协议: 正式协议是一个命名的方法列表。 采用协议意味着必须实现该协议的所有方法。否则,编译器会发出警告。 正式协议就像JAVA中的接口一样。 声明协议: @protocal NSCopying -(id) copywithzone:(NSZone *) zone; //方法列表 @end 采用协议: @interface Car:NSObject //中括号中是要实现的协议列表 {//实例变量列表} //方法列表 @end 在objective-c 2.0中,有新特性:@optional, @required
  • 30. Q & A
  • 31. (本页无文本内容)