SlideShare a Scribd company logo
1 of 31
分享人:李航 ( 酷酷 ) http://weibo.com/lidaohang 欢迎大家参与 " 爱疯了 " 技术交流分享
1.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++ : 不支持操作符重载,模版和多重继承。
2.Objective-C 与 C++ 每个 Objective-C 对象都隐藏着一个数据结构,它的第一个成员变量或者说实例变量是 "isa" 指针。  isa 指针指向的是对象的类,这个类也是一个对象,有自己的权限,是根据类的定义编译而来的。类对象负责维护一个方法调度表,该表实际上是由指向类方法的指针组成的。类对象中还保留一个超类的指针,该指针又有自己的方法调度表和超类。  isa 指针对消息分发机制和 cocoa 对象的动态能力很重要。 C++  与 Objective-C 最大的区别在于分配方法的机制不同, C++  是基于虚拟表机制确定虚函数调用什么代码,而 Objective-C  使用运行时,函数进入各种类结构中查找相应的代码以供调用。这么一比,很明显  C++  的效率要高的多,正因如此,我们要明确的是, Objective-C  牺牲了一定的速度和安全,换来了灵活和便捷,这是一种权衡利弊的做法。
3.  常见语法说明  1. 头文件引用使用  #import  “  文件名”或者  #import <  文件名 > 的形式以确保每个头文件仅被包含一次 。 2. 类声明以  @interface 类 名 : 继承类 开头,以  @end   结尾,类实现以  @implementation 类 名 开头,以  @end   结尾。  3. 实例方法,即成员方法,在方法名前面添加一个减号 ( - ) ;类方法,在方法名前面添加一个加号  ( + )  。  4. 类方法的调用格式为  [ 类名 类方法 ] ,成员方法调用格式为  [ 实例名  实例方法 ] ,这种模式在 ObjC  中被称为消息机制, [  对象  消息 ] 即给对象发送了一个消息,产生的效果就是该对象调用了该类中定义的对应的实例方法 。 5. 类属性 :  NSString *aString; 6. 协议 @ protocol  IQuery -(void) Query:(NSString*) sql; @end
头文件: #import <Foundation/Foundation.h> @interface MemFoo: NSObject { // 属性 int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str;  //重载 NSObject 类初始化方法 @end
实现类: @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:@&quot;hello&quot;]; [myMem release]; }
4 . 属性的介绍与使用 : @property  类型  名字 属性主要分为三类:  1.  读写属性( readwrite /  readonly )  2. Setter 属性 ( assign / retain / copy ) 3.  原子属性 ( atomicity/nonatomic ) 如果属性是对象类型,你需要使用 retain,assign,copy 参数,表示 setter 方法内部实现的时候,持有对象的方式。其中 retain 就是增加引用计数,强引用类型。 assign 就是变量的直接赋值,弱引用类型,也是默认值。 copy 就是把 setter 的参数复制一遍,再赋给成员变量。 如果你不给出持有对象的方式,编译器就会给出警告。 原子属性中, atomic 是默认值,表示属性是原子的,支持多线程并发访问(在 setter 实现中加入了同步锁),后者是非原子的,适合在非多线程环境中提升效率,没有加入同步锁。
示例代码如下 : #import <Foundation/Foundation.h> @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;
5. 重载父类初始化方法 : @interface MemFoo: NSObject  {  int x;  NSString* name;  }  @property int x;  @property (copy) NSString* name;  -(MemFoo*)init:(int) n:(NSString*)str;  //重载 NSObject 类初始化方法  @end
@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:@&quot;hello&quot;];  [myMem autorelease];  NSLog(@&quot;00000000 x is = %x, name is =%@ &quot;,[myMem x],[myMem name]);  [pool drain];  return 0;  }
6. 字符串类各种操作方法 NSString  *str=@&quot;every day  keep up&quot;;  NSMutableString *mstr;  NSRange substr;  mstr=[NSMutableString stringWithString:str]; // 初始化可变字符串  [mstr insertString:@&quot;xiaxia&quot; atIndex:[mstr length]];// 在指定位置插入字符串  [mstr appendString:@&quot;append&quot;];  //链接新字符串  [mstr deleteCharactersInRange:NSMakeRange(1, 3)]; //删除某个 range 的字符串  [mstr setString:@&quot;new&quot;];  [mstr replaceCharactersInRange:NSMakeRange(1, 2) withString:@&quot;ame&quot;];  //替换某个位置字符串  NSString *search=@&quot;am&quot;;  NSString *replace=@&quot;helleee&quot;;  substr=[mstr rangeOfString:search];  if (substr.location!=NSNotFound) {  [mstr replaceCharactersInRange:substr withString:replace];  } //查找替换某些字符串  search=@&quot;e&quot;;  replace=@&quot;a&quot;;  substr=[mstr rangeOfString:search];  while (substr.location!=NSNotFound) {  [mstr replaceCharactersInRange:substr withString:replace];  substr=[mstr rangeOfString:search];  }  NSLog(@&quot;mstr is:  %@&quot;,mstr);
7. 数字类的各种操作方法 NSNumber  *myNumber, *floatNumber, *interNumber;  NSInteger myInt;  myNumber=NULL;  interNumber=NULL;  floatNumber=NULL;  interNumber=[NSNumber numberWithInt:110];  //初始化整数  myInt=[interNumber integerValue];  //获取整数值  NSLog(@&quot;myInt is %li&quot;, (long)myInt);  floatNumber=[NSNumber numberWithFloat:100.00];  NSLog(@&quot;float number is %g&quot;, [floatNumber floatValue]);  myNumber=[NSNumber numberWithChar:'A'];  NSLog(@&quot;char number is %x&quot;, [myNumber charValue]);  if ([interNumber isEqualToNumber:floatNumber]==TRUE) {  //比较两个数  NSLog(@&quot;HAHAHA&quot;);  }
8. 集合类的各种操作方法 NSMutableArray *weekName=[NSMutableArray  arrayWithObjects:@&quot;MM&quot;,@&quot;TT&quot;,@&quot;WW&quot;,nil];  int i=0;  for(i=0;i<3;i++)  {  NSLog(@&quot;%i %@&quot;, i+1,[weekName objectAtIndex:i]);  }  NSMutableArray *MutableArray =  [ NSMutableArray alloc] init]; NSArray *array = [NSArray arrayWithObjects: @&quot;a&quot;,@&quot;b&quot;,@&quot;c&quot;,nil]; NSLog(@&quot;array:%@&quot;,array); MutableArray = [NSMutableArray arrayWithArray:array]; NSLog(@&quot;MutableArray:%@&quot;,MutableArray); array1 = [NSArray arrayWithArray:array]; NSLog(@&quot;array1:%@&quot;,array1);
9. 文件类的各种操作方法 NSString  *fName=@&quot;testfile.m&quot;;  NSFileManager *fm=NULL;  NSDictionary  *dict=NULL;  fm=[NSFileManager defaultManager];  if ([fm fileExistsAtPath:fName]==NO) {  NSLog(@&quot;file not exist!&quot;);  return 1;  }  if ([fm copyPath:fName toPath:@&quot;newfile&quot; handler:nil]==NO) {  NSLog(@&quot;copy failed!&quot;);  }  if ([fm movePath:@&quot;newfile&quot; toPath:@&quot;newfolder&quot; handler:nil]==NO) {  NSLog(@&quot;move failed&quot;);  }  if ((dict=[fm fileAttributesAtPath:@&quot;newfolder&quot; traverseLink:NO])==nil) {  NSLog(@&quot;get file attributes failed&quot;);  }  NSLog(@&quot;file size is %i bytes&quot;,[[dict objectForKey:NSFileSize] intValue]);  if ([fm removeFileAtPath:@&quot;newfolder&quot; handler:nil]==YES) {  NSLog(@&quot;remove successful!&quot;);  }
10. 协议 正式协议 (protocal) 其实就是非正式协议 (interface) 换了一种写法而已,看上去更正规一些,语义上更强烈一些:要求采用该协议的类,”必须”实现协议中约定的方法。但是比较娱乐的是,即使是号称正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。(当然正式协议也有它存在的意义,后面会提到) 这里我们定义一个 IQuery 的协议 协议: @protocol IQuery -(void) Query:(NSString*) sql; @end 头文件类: @interface DBQuery : NSObject<IQuery> { } @end 实现类: @implementation DBQuery -(void) Query:(NSString *)sql { NSLog(@”Query is called. sql:%@”,sql); } @end
11. 内存管理 移动开发的特点:资源的有限性。作为手持设备, iphone 的内存与传统的 PC 不可同日而语,这就要求我们在开发 IOS 程序的过程中,首要也是最重要的任务就是解决内存释放问题,本文将在网络上搜集的关于内存管理的经验予以分享。 开发 iPhone  应用程序并不难,基本上就是三个词  - “memory, memory, memory”  。 iPhone OS  对内存的要求很严格,有 memory leak  ,杀掉; 内存使用超限额,杀掉。一个经过测试的程序,在使用过程中 90% 以上的崩溃都是内存问题造成的。在这里简单总结一下 Objective-C  内存管理。 一、基本概念 Objective-C  的内存管理基于引用计数 (Reference Count) 这种非常常用的技术。简单讲,如果要使用一个对象,并希望确保在使用期间对象不被释放,需要通过函数调用来取得“所有权”,使用结束后再调用 函数释放“所有权”。“所有权”的获得和释放,对应引用计数的增加和减少,为正数时代表对象还有引用,为零时代表可以释放。
11. 内存管理 1 、函数 获得所有权的函数包括 alloc -  创建对象是调用 alloc ,为对象分配内存,对象引用计数加一。 copy -  拷贝一个对象,返回新对象,引用计数加一。 retain -  引用计数加一,获得对象的所有权。 另外,名字中带有 alloc, copy, retain  字串的函数也都认为会为引用计数加一。 释放所有权的函数包括 release -  引用计数减一,释放所有权。如果引用计数减到零,对象会被释放。 autorelease -  在未来某个时机释放。下面具体解释。 autorelease 在某些情况下,并不想取得所有权,又不希望对象被释放。例如在一个函数中生成了一个新对象并返回,函数本身并不希望取得所有权,因为取得后再没有机 会释放(除非创造出新的调用规则,而调用规则是一切混乱的开始),又不可能在函数内释放,可以借助 autorelease  。所谓 autorelease ,  可以理解为把所有权交给一个外在的系统(这个系统实际上叫 autorelease pool ),由它来管理该对象的释放。通常认为交给  autorelease  的对象在当前 event loop  中都是有效的。也可以自己创建 NSAutoreleasePool  来控制 autorelease 的过程。 据苹果的人说, autorelease 效率不高,所以能自己 release 的地方,尽量自己 release ,不要随便交给 autorelease 来处理。
11. 内存管理 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 是内容拷贝。
11. 内存管理 内存管理算是学习一门语言时,比较难但是最重要的一部分。  object - c  中的 Foundation 框架带入了引用计数这一概念和思想来管理内存。极大的减轻了程序员内存管理的负担,你不必再那么小心翼翼。  引用计数的概念如下,创建对象时,将它的引用计数设置为 1 ,每次必须保持该对象时,就发送一条 retain 消息,使其引用计数加 1 。 Foundation 框架提供的其他一些方法也可以增加对象的引用计数,例如,把对象添加到数组中。 不需要对象时,可以通过发送一条 release 消息,使对象的引用计数减 1 。 当对象的引用计数到 0 时,系统就知道不再需要这个对象了,因此系统会释放( deallocates )它的内存。这是通过一条 dealloc  消息而实现的。 首先,我们看下面的代码示例:
11. 内存管理 NSString *str0=@&quot;str0&quot;;  NSString *str1=[NSString stringWithString:@&quot;str1&quot;];  NSMutableString *str2=[NSMutableString stringWithString:@&quot;str2&quot;];  NSMutableArray *strArray=[NSMutableArray array];  NSLog(@&quot;%x, %x, %x&quot;, [str0 retainCount],[str1 retainCount],[str2 retainCount]);  [strArray  addObject:str0];  [strArray  addObject:str1];  [strArray  addObject:str2];  NSLog(@&quot;%x, %x, %x&quot;, [str0 retainCount],[str1 retainCount],[str2 retainCount]);  [str0 retain];  [str1 retain];  [str2 retain];  NSLog(@&quot;%x, %x, %x&quot;, [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 被设置为常量字符串 @&quot;str2&quot; 的副本。通过发送 stringWithstring 消息来实现。
11. 内存管理 自动释放池,在 Objective-C 模块中,发挥着重要作用,能够帮助我们清理很多内存。但是它也不是万能的,也必须要合理小心的使用。 本文通过一个示例代码,来介绍下自动释放池的用法和注意事项。 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  MemFoo *pMem=[[MemFoo alloc]init];  NSLog(@&quot;aaaaa  retaincount: %d&quot;, [pMem retainCount]);  [pool drain];  pool=[[NSAutoreleasePool alloc]init];  [pMem autorelease];  //不会增加引用计数  NSLog(@&quot;bbbbb  retaincount: %d&quot;,[pMem retainCount]);  [pMem retain];  NSLog(@&quot;ccccc  retaincount: %d&quot;,[pMem retainCount]);  [pool drain];  NSLog(@&quot;ddddd  retaincount: %d&quot;,[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 所以,除了依赖于自动释放池外,对于额外的增加引用,必须由自己去亲自释放。
12. 总结 : 与 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: 是一种泛型,用于表示任何种类的对象。
12. 总结 : 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<IA,IB...> // 类名(类别名):父类 < 协议 >
总结 : 1.Foundation kit: Cocoa 是由两部分框架组成的: foundation kit [ 包括一些基础类 ] 和  application kit. 【包括用户接口对象和高级类】 创建字符串: NSString *test; test=[NSString stringWithFormat:@&quot;i'm %d years old!&quot;,23]; 若在声明方法时在方法前面添加了加号,那就表示把这个方法定义为类方法【这个方法属于类对象,而不是类的实例对象。】 NSArray 类:可以存放任意类型的对象 . 它有两个限制: 1.  它只能存储 objective-c 的对象,但不能存储 C 中的基本数据类型,如 int , float, enum, struct 等。 2. 不能存储 nil( 对象的零值或 NULL 值 ) ;【因为在创建 NSArray 时,要在列表结尾添加 nil 代表列表结束。】 创建 NSArray : NSArray *array; array=[NSArray arrayWithObjects:@&quot;one&quot;,@&quot;two&quot;,nil]; NSString, NSMutableString 类; 【 NSString 是不可变的,即一旦创建完成,就不能通过删除字符或添加字符的方式来改变它;
总结: 而 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: 自动释放内存池。
总结: 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];
总结: 内存管理黄金准则: 只有通过 alloc, new 和  copy 方法创建的对象,才需要程序员负责向该对象发送 release 或 autorelease 消息。 而通过其他方法获得的对象,则默认为已经被设置为自动释放,所以不需要程序员做任何操作了。 在 objective-c 2.0 中有垃圾回收机制, 如果要对某个项目使用垃圾回收: 项目信息 --build 选项卡 -- 查询 &quot;garb&quot;, 出现“ objective-c Garbage Collection”, 将其值设置为“ required[-fobjc-gc-only]” 启用垃圾回收后,通常的内存管理命令全都变成了空操作指令,不执行任何操作。 开发 iphone 软件,不能使用垃圾回收。 对象初始化 两种创建新对象的方法: [ 类名  new] [[ 类名  alloc] init] 这两种方法是等价的,但 cocoa 的惯例是使用后者。 alloc 在为对象分配空间的同时,将这块内存初始化为 0 ; Init 方法:初始化实例变量,使对象处于可用状态。 [ 返回类型为 id,  返回的值描述了被初始化的对象 ] 使用 new 创建新对象时,系统要完成两个步骤: 1.  为对象分配内存,即对象获得一个用来存放其实例变量的内存块; 2.  自动调用 init 方法,让该对象处于可用状态。
总结: 3. 类别: 类别( category )是一种为现有的类添加新方法的方式。类别的声明: @interface NSString (NumberConvenience) // 类名 (类别名) -(NSNumber) lengthAsNumber; // 扩充方法声明 @end 使用时使用原来的类名,就可以调用他的所有类别中的方法。 类别的局限性: 1.  不能向类中添加新的实例变量; 2.  在类别中的方法若与类中现有的方法重名,则类中的方法不可用,被类别中的新方法取代。 类别的作用: 1.  将类的实现分散到多个文件或框架中; 2.  创建对私有方法的前向引用; 【 Cocoa 中没有真正的私有方法,则实现私有方法类似功能的方法为: 先在类别中声明方法;然后到现有类的实现中实现该方法。 这样这个类中的其他方法可以使用该方法,而其他外部的类就不会知道该方法的存在了。】 3.  向对象添加非正式协议。 【创建一个 NSObject 的类别称为创建一个非正式协议。】 委托 delegate 是一种对象,另一个类的对象会要求委托对象执行它的某些操作。 受委托对象在某个时间(某个事件触发)时,会自动通知委托对象执行委托方法。 选择器: @selector () : 选择器只是一个方法名称,但它以 objective-c 运行时使用的特殊方式编码,以快速执行查询。圆括号中的内容是方法名。 所以 Car 类的 setEngine: 方法的选择器是: @selector ( setEngine: 受委托对象如何知道其委托对象是否能处理它(受委托对象)发送给它(委托对象)的消息? 通过选择器,受委托对象先检查委托对象,询问其是否能响应该选择器。如果能,则向它发送消息。
总结: 3. 协议: 正式协议是一个命名的方法列表。 采用协议意味着必须实现该协议的所有方法。否则,编译器会发出警告。 正式协议就像 JAVA 中的接口一样。 声明协议: @protocal NSCopying -(id) copywithzone:(NSZone *) zone; // 方法列表 @end 采用协议: @interface Car:NSObject <NSCopying,NSCoding> // 中括号中是要实现的协议列表 {// 实例变量列表 } // 方法列表 @end 在 objective-c 2.0 中,有新特性: @optional, @required
Q & A
 

More Related Content

What's hot

JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1Sheng-Han Su
 
深入淺出 Web 容器 - Tomcat 原始碼分析
深入淺出 Web 容器  - Tomcat 原始碼分析深入淺出 Web 容器  - Tomcat 原始碼分析
深入淺出 Web 容器 - Tomcat 原始碼分析Justin Lin
 
jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习fangdeng
 
OpenEJB - 另一個選擇
OpenEJB - 另一個選擇OpenEJB - 另一個選擇
OpenEJB - 另一個選擇Justin Lin
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错jeffz
 
Python learn guide
Python learn guidePython learn guide
Python learn guiderobin yang
 
從 Singleton 談 constructor
從 Singleton 談 constructor從 Singleton 談 constructor
從 Singleton 談 constructorLuba Tang
 
C++11 smart pointers
C++11 smart pointersC++11 smart pointers
C++11 smart pointerschchwy Chang
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7Justin Lin
 
冲浪 Object-c
冲浪 Object-c冲浪 Object-c
冲浪 Object-cjeff kit
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记yiditushe
 
JAVA内存泄漏及诊断
JAVA内存泄漏及诊断JAVA内存泄漏及诊断
JAVA内存泄漏及诊断ivannotes
 
Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式ZongYing Lyu
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLin Yo-An
 
JavaScript 教程
JavaScript 教程JavaScript 教程
JavaScript 教程Bobby Zhou
 
由一个简单的程序谈起――之五(精华)
由一个简单的程序谈起――之五(精华)由一个简单的程序谈起――之五(精华)
由一个简单的程序谈起――之五(精华)yiditushe
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)Leo Hui
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法crasysatan
 
05 MapKit and Text Input
05 MapKit and Text Input05 MapKit and Text Input
05 MapKit and Text InputTom Fan
 

What's hot (20)

JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1
 
深入淺出 Web 容器 - Tomcat 原始碼分析
深入淺出 Web 容器  - Tomcat 原始碼分析深入淺出 Web 容器  - Tomcat 原始碼分析
深入淺出 Web 容器 - Tomcat 原始碼分析
 
jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习
 
OpenEJB - 另一個選擇
OpenEJB - 另一個選擇OpenEJB - 另一個選擇
OpenEJB - 另一個選擇
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错
 
Python learn guide
Python learn guidePython learn guide
Python learn guide
 
從 Singleton 談 constructor
從 Singleton 談 constructor從 Singleton 談 constructor
從 Singleton 談 constructor
 
C++11 smart pointers
C++11 smart pointersC++11 smart pointers
C++11 smart pointers
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
 
冲浪 Object-c
冲浪 Object-c冲浪 Object-c
冲浪 Object-c
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
 
JAVA内存泄漏及诊断
JAVA内存泄漏及诊断JAVA内存泄漏及诊断
JAVA内存泄漏及诊断
 
Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHP
 
JavaScript 教程
JavaScript 教程JavaScript 教程
JavaScript 教程
 
由一个简单的程序谈起――之五(精华)
由一个简单的程序谈起――之五(精华)由一个简单的程序谈起――之五(精华)
由一个简单的程序谈起――之五(精华)
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
 
05 MapKit and Text Input
05 MapKit and Text Input05 MapKit and Text Input
05 MapKit and Text Input
 

Viewers also liked

Sustainability Report 2009
Sustainability Report 2009Sustainability Report 2009
Sustainability Report 2009rjschueler
 
La importanciade los computadores
La importanciade los computadoresLa importanciade los computadores
La importanciade los computadoresandrez_f_lopez
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Lucien Li
 
Sustainability Presentation
Sustainability PresentationSustainability Presentation
Sustainability Presentationrjschueler
 
深入学习Mongo db
深入学习Mongo db深入学习Mongo db
深入学习Mongo dbLucien Li
 

Viewers also liked (6)

Sustainability Report 2009
Sustainability Report 2009Sustainability Report 2009
Sustainability Report 2009
 
La importanciade los computadores
La importanciade los computadoresLa importanciade los computadores
La importanciade los computadores
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案
 
Calcium
CalciumCalcium
Calcium
 
Sustainability Presentation
Sustainability PresentationSustainability Presentation
Sustainability Presentation
 
深入学习Mongo db
深入学习Mongo db深入学习Mongo db
深入学习Mongo db
 

Similar to iPhone,ios,Object-c基础入门

02 Objective-C
02 Objective-C02 Objective-C
02 Objective-CTom Fan
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013Michael Pan
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanupted-xu
 
Automate with Ansible basic (3/e)
Automate with Ansible basic (3/e)Automate with Ansible basic (3/e)
Automate with Ansible basic (3/e)Chu-Siang Lai
 
現代 IT 人一定要知道的 Ansible 自動化組態技巧
現代 IT 人一定要知道的 Ansible 自動化組態技巧現代 IT 人一定要知道的 Ansible 自動化組態技巧
現代 IT 人一定要知道的 Ansible 自動化組態技巧Chu-Siang Lai
 
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构裕波 周
 
4.2第四章 swarm代码剖析 可选补充课程
4.2第四章 swarm代码剖析 可选补充课程4.2第四章 swarm代码剖析 可选补充课程
4.2第四章 swarm代码剖析 可选补充课程zhang shuren
 
iOS程序设计-数据持久化
iOS程序设计-数据持久化iOS程序设计-数据持久化
iOS程序设计-数据持久化qiyutan
 
16 CoreData
16 CoreData16 CoreData
16 CoreDataTom Fan
 
Android resource-management
Android resource-managementAndroid resource-management
Android resource-managementLucas Xu
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非Tony Deng
 
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用FLASH开发者交流会
 
Moodle 项目帮助手册:程序编写准则
Moodle 项目帮助手册:程序编写准则Moodle 项目帮助手册:程序编写准则
Moodle 项目帮助手册:程序编写准则YUCHENG HU
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档yiditushe
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)RANK LIU
 
Java Script 引擎技术
Java Script 引擎技术Java Script 引擎技术
Java Script 引擎技术bigqiang zou
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程zhangdaiping
 

Similar to iPhone,ios,Object-c基础入门 (20)

02 Objective-C
02 Objective-C02 Objective-C
02 Objective-C
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanup
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
Automate with Ansible basic (3/e)
Automate with Ansible basic (3/e)Automate with Ansible basic (3/e)
Automate with Ansible basic (3/e)
 
現代 IT 人一定要知道的 Ansible 自動化組態技巧
現代 IT 人一定要知道的 Ansible 自動化組態技巧現代 IT 人一定要知道的 Ansible 自動化組態技巧
現代 IT 人一定要知道的 Ansible 自動化組態技巧
 
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构
 
4.2第四章 swarm代码剖析 可选补充课程
4.2第四章 swarm代码剖析 可选补充课程4.2第四章 swarm代码剖析 可选补充课程
4.2第四章 swarm代码剖析 可选补充课程
 
iOS程序设计-数据持久化
iOS程序设计-数据持久化iOS程序设计-数据持久化
iOS程序设计-数据持久化
 
16 CoreData
16 CoreData16 CoreData
16 CoreData
 
Android resource-management
Android resource-managementAndroid resource-management
Android resource-management
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用
详解AS3的内存管理机制,有效释放FLASH内存,减少资源占用
 
Moodle 项目帮助手册:程序编写准则
Moodle 项目帮助手册:程序编写准则Moodle 项目帮助手册:程序编写准则
Moodle 项目帮助手册:程序编写准则
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档
 
Sun java
Sun javaSun java
Sun java
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)
 
Java Script 引擎技术
Java Script 引擎技术Java Script 引擎技术
Java Script 引擎技术
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程
 

iPhone,ios,Object-c基础入门

  • 1. 分享人:李航 ( 酷酷 ) http://weibo.com/lidaohang 欢迎大家参与 &quot; 爱疯了 &quot; 技术交流分享
  • 2. 1.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. 2.Objective-C 与 C++ 每个 Objective-C 对象都隐藏着一个数据结构,它的第一个成员变量或者说实例变量是 &quot;isa&quot; 指针。 isa 指针指向的是对象的类,这个类也是一个对象,有自己的权限,是根据类的定义编译而来的。类对象负责维护一个方法调度表,该表实际上是由指向类方法的指针组成的。类对象中还保留一个超类的指针,该指针又有自己的方法调度表和超类。 isa 指针对消息分发机制和 cocoa 对象的动态能力很重要。 C++ 与 Objective-C 最大的区别在于分配方法的机制不同, C++ 是基于虚拟表机制确定虚函数调用什么代码,而 Objective-C 使用运行时,函数进入各种类结构中查找相应的代码以供调用。这么一比,很明显 C++ 的效率要高的多,正因如此,我们要明确的是, Objective-C 牺牲了一定的速度和安全,换来了灵活和便捷,这是一种权衡利弊的做法。
  • 4. 3. 常见语法说明 1. 头文件引用使用 #import “ 文件名”或者 #import < 文件名 > 的形式以确保每个头文件仅被包含一次 。 2. 类声明以 @interface 类 名 : 继承类 开头,以 @end 结尾,类实现以 @implementation 类 名 开头,以 @end 结尾。 3. 实例方法,即成员方法,在方法名前面添加一个减号 ( - ) ;类方法,在方法名前面添加一个加号 ( + ) 。 4. 类方法的调用格式为 [ 类名 类方法 ] ,成员方法调用格式为 [ 实例名 实例方法 ] ,这种模式在 ObjC 中被称为消息机制, [ 对象 消息 ] 即给对象发送了一个消息,产生的效果就是该对象调用了该类中定义的对应的实例方法 。 5. 类属性 : NSString *aString; 6. 协议 @ protocol IQuery -(void) Query:(NSString*) sql; @end
  • 5. 头文件: #import <Foundation/Foundation.h> @interface MemFoo: NSObject { // 属性 int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str; //重载 NSObject 类初始化方法 @end
  • 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:@&quot;hello&quot;]; [myMem release]; }
  • 7. 4 . 属性的介绍与使用 : @property 类型 名字 属性主要分为三类: 1. 读写属性( readwrite / readonly ) 2. Setter 属性 ( assign / retain / copy ) 3. 原子属性 ( atomicity/nonatomic ) 如果属性是对象类型,你需要使用 retain,assign,copy 参数,表示 setter 方法内部实现的时候,持有对象的方式。其中 retain 就是增加引用计数,强引用类型。 assign 就是变量的直接赋值,弱引用类型,也是默认值。 copy 就是把 setter 的参数复制一遍,再赋给成员变量。 如果你不给出持有对象的方式,编译器就会给出警告。 原子属性中, atomic 是默认值,表示属性是原子的,支持多线程并发访问(在 setter 实现中加入了同步锁),后者是非原子的,适合在非多线程环境中提升效率,没有加入同步锁。
  • 8. 示例代码如下 : #import <Foundation/Foundation.h> @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. 5. 重载父类初始化方法 : @interface MemFoo: NSObject { int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str; //重载 NSObject 类初始化方法 @end
  • 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:@&quot;hello&quot;]; [myMem autorelease]; NSLog(@&quot;00000000 x is = %x, name is =%@ &quot;,[myMem x],[myMem name]); [pool drain]; return 0; }
  • 11. 6. 字符串类各种操作方法 NSString *str=@&quot;every day keep up&quot;; NSMutableString *mstr; NSRange substr; mstr=[NSMutableString stringWithString:str]; // 初始化可变字符串 [mstr insertString:@&quot;xiaxia&quot; atIndex:[mstr length]];// 在指定位置插入字符串 [mstr appendString:@&quot;append&quot;]; //链接新字符串 [mstr deleteCharactersInRange:NSMakeRange(1, 3)]; //删除某个 range 的字符串 [mstr setString:@&quot;new&quot;]; [mstr replaceCharactersInRange:NSMakeRange(1, 2) withString:@&quot;ame&quot;]; //替换某个位置字符串 NSString *search=@&quot;am&quot;; NSString *replace=@&quot;helleee&quot;; substr=[mstr rangeOfString:search]; if (substr.location!=NSNotFound) { [mstr replaceCharactersInRange:substr withString:replace]; } //查找替换某些字符串 search=@&quot;e&quot;; replace=@&quot;a&quot;; substr=[mstr rangeOfString:search]; while (substr.location!=NSNotFound) { [mstr replaceCharactersInRange:substr withString:replace]; substr=[mstr rangeOfString:search]; } NSLog(@&quot;mstr is: %@&quot;,mstr);
  • 12. 7. 数字类的各种操作方法 NSNumber *myNumber, *floatNumber, *interNumber; NSInteger myInt; myNumber=NULL; interNumber=NULL; floatNumber=NULL; interNumber=[NSNumber numberWithInt:110]; //初始化整数 myInt=[interNumber integerValue]; //获取整数值 NSLog(@&quot;myInt is %li&quot;, (long)myInt); floatNumber=[NSNumber numberWithFloat:100.00]; NSLog(@&quot;float number is %g&quot;, [floatNumber floatValue]); myNumber=[NSNumber numberWithChar:'A']; NSLog(@&quot;char number is %x&quot;, [myNumber charValue]); if ([interNumber isEqualToNumber:floatNumber]==TRUE) { //比较两个数 NSLog(@&quot;HAHAHA&quot;); }
  • 13. 8. 集合类的各种操作方法 NSMutableArray *weekName=[NSMutableArray arrayWithObjects:@&quot;MM&quot;,@&quot;TT&quot;,@&quot;WW&quot;,nil]; int i=0; for(i=0;i<3;i++) { NSLog(@&quot;%i %@&quot;, i+1,[weekName objectAtIndex:i]); } NSMutableArray *MutableArray = [ NSMutableArray alloc] init]; NSArray *array = [NSArray arrayWithObjects: @&quot;a&quot;,@&quot;b&quot;,@&quot;c&quot;,nil]; NSLog(@&quot;array:%@&quot;,array); MutableArray = [NSMutableArray arrayWithArray:array]; NSLog(@&quot;MutableArray:%@&quot;,MutableArray); array1 = [NSArray arrayWithArray:array]; NSLog(@&quot;array1:%@&quot;,array1);
  • 14. 9. 文件类的各种操作方法 NSString *fName=@&quot;testfile.m&quot;; NSFileManager *fm=NULL; NSDictionary *dict=NULL; fm=[NSFileManager defaultManager]; if ([fm fileExistsAtPath:fName]==NO) { NSLog(@&quot;file not exist!&quot;); return 1; } if ([fm copyPath:fName toPath:@&quot;newfile&quot; handler:nil]==NO) { NSLog(@&quot;copy failed!&quot;); } if ([fm movePath:@&quot;newfile&quot; toPath:@&quot;newfolder&quot; handler:nil]==NO) { NSLog(@&quot;move failed&quot;); } if ((dict=[fm fileAttributesAtPath:@&quot;newfolder&quot; traverseLink:NO])==nil) { NSLog(@&quot;get file attributes failed&quot;); } NSLog(@&quot;file size is %i bytes&quot;,[[dict objectForKey:NSFileSize] intValue]); if ([fm removeFileAtPath:@&quot;newfolder&quot; handler:nil]==YES) { NSLog(@&quot;remove successful!&quot;); }
  • 15. 10. 协议 正式协议 (protocal) 其实就是非正式协议 (interface) 换了一种写法而已,看上去更正规一些,语义上更强烈一些:要求采用该协议的类,”必须”实现协议中约定的方法。但是比较娱乐的是,即使是号称正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。(当然正式协议也有它存在的意义,后面会提到) 这里我们定义一个 IQuery 的协议 协议: @protocol IQuery -(void) Query:(NSString*) sql; @end 头文件类: @interface DBQuery : NSObject<IQuery> { } @end 实现类: @implementation DBQuery -(void) Query:(NSString *)sql { NSLog(@”Query is called. sql:%@”,sql); } @end
  • 16. 11. 内存管理 移动开发的特点:资源的有限性。作为手持设备, iphone 的内存与传统的 PC 不可同日而语,这就要求我们在开发 IOS 程序的过程中,首要也是最重要的任务就是解决内存释放问题,本文将在网络上搜集的关于内存管理的经验予以分享。 开发 iPhone 应用程序并不难,基本上就是三个词 - “memory, memory, memory” 。 iPhone OS 对内存的要求很严格,有 memory leak ,杀掉; 内存使用超限额,杀掉。一个经过测试的程序,在使用过程中 90% 以上的崩溃都是内存问题造成的。在这里简单总结一下 Objective-C 内存管理。 一、基本概念 Objective-C 的内存管理基于引用计数 (Reference Count) 这种非常常用的技术。简单讲,如果要使用一个对象,并希望确保在使用期间对象不被释放,需要通过函数调用来取得“所有权”,使用结束后再调用 函数释放“所有权”。“所有权”的获得和释放,对应引用计数的增加和减少,为正数时代表对象还有引用,为零时代表可以释放。
  • 17. 11. 内存管理 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. 11. 内存管理 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. 11. 内存管理 内存管理算是学习一门语言时,比较难但是最重要的一部分。 object - c 中的 Foundation 框架带入了引用计数这一概念和思想来管理内存。极大的减轻了程序员内存管理的负担,你不必再那么小心翼翼。 引用计数的概念如下,创建对象时,将它的引用计数设置为 1 ,每次必须保持该对象时,就发送一条 retain 消息,使其引用计数加 1 。 Foundation 框架提供的其他一些方法也可以增加对象的引用计数,例如,把对象添加到数组中。 不需要对象时,可以通过发送一条 release 消息,使对象的引用计数减 1 。 当对象的引用计数到 0 时,系统就知道不再需要这个对象了,因此系统会释放( deallocates )它的内存。这是通过一条 dealloc 消息而实现的。 首先,我们看下面的代码示例:
  • 20. 11. 内存管理 NSString *str0=@&quot;str0&quot;; NSString *str1=[NSString stringWithString:@&quot;str1&quot;]; NSMutableString *str2=[NSMutableString stringWithString:@&quot;str2&quot;]; NSMutableArray *strArray=[NSMutableArray array]; NSLog(@&quot;%x, %x, %x&quot;, [str0 retainCount],[str1 retainCount],[str2 retainCount]); [strArray addObject:str0]; [strArray addObject:str1]; [strArray addObject:str2]; NSLog(@&quot;%x, %x, %x&quot;, [str0 retainCount],[str1 retainCount],[str2 retainCount]); [str0 retain]; [str1 retain]; [str2 retain]; NSLog(@&quot;%x, %x, %x&quot;, [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 被设置为常量字符串 @&quot;str2&quot; 的副本。通过发送 stringWithstring 消息来实现。
  • 21. 11. 内存管理 自动释放池,在 Objective-C 模块中,发挥着重要作用,能够帮助我们清理很多内存。但是它也不是万能的,也必须要合理小心的使用。 本文通过一个示例代码,来介绍下自动释放池的用法和注意事项。 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; MemFoo *pMem=[[MemFoo alloc]init]; NSLog(@&quot;aaaaa retaincount: %d&quot;, [pMem retainCount]); [pool drain]; pool=[[NSAutoreleasePool alloc]init]; [pMem autorelease]; //不会增加引用计数 NSLog(@&quot;bbbbb retaincount: %d&quot;,[pMem retainCount]); [pMem retain]; NSLog(@&quot;ccccc retaincount: %d&quot;,[pMem retainCount]); [pool drain]; NSLog(@&quot;ddddd retaincount: %d&quot;,[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. 12. 总结 : 与 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. 12. 总结 : 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<IA,IB...> // 类名(类别名):父类 < 协议 >
  • 24. 总结 : 1.Foundation kit: Cocoa 是由两部分框架组成的: foundation kit [ 包括一些基础类 ] 和 application kit. 【包括用户接口对象和高级类】 创建字符串: NSString *test; test=[NSString stringWithFormat:@&quot;i'm %d years old!&quot;,23]; 若在声明方法时在方法前面添加了加号,那就表示把这个方法定义为类方法【这个方法属于类对象,而不是类的实例对象。】 NSArray 类:可以存放任意类型的对象 . 它有两个限制: 1. 它只能存储 objective-c 的对象,但不能存储 C 中的基本数据类型,如 int , float, enum, struct 等。 2. 不能存储 nil( 对象的零值或 NULL 值 ) ;【因为在创建 NSArray 时,要在列表结尾添加 nil 代表列表结束。】 创建 NSArray : NSArray *array; array=[NSArray arrayWithObjects:@&quot;one&quot;,@&quot;two&quot;,nil]; NSString, NSMutableString 类; 【 NSString 是不可变的,即一旦创建完成,就不能通过删除字符或添加字符的方式来改变它;
  • 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. 总结: 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. 总结: 内存管理黄金准则: 只有通过 alloc, new 和 copy 方法创建的对象,才需要程序员负责向该对象发送 release 或 autorelease 消息。 而通过其他方法获得的对象,则默认为已经被设置为自动释放,所以不需要程序员做任何操作了。 在 objective-c 2.0 中有垃圾回收机制, 如果要对某个项目使用垃圾回收: 项目信息 --build 选项卡 -- 查询 &quot;garb&quot;, 出现“ objective-c Garbage Collection”, 将其值设置为“ required[-fobjc-gc-only]” 启用垃圾回收后,通常的内存管理命令全都变成了空操作指令,不执行任何操作。 开发 iphone 软件,不能使用垃圾回收。 对象初始化 两种创建新对象的方法: [ 类名 new] [[ 类名 alloc] init] 这两种方法是等价的,但 cocoa 的惯例是使用后者。 alloc 在为对象分配空间的同时,将这块内存初始化为 0 ; Init 方法:初始化实例变量,使对象处于可用状态。 [ 返回类型为 id, 返回的值描述了被初始化的对象 ] 使用 new 创建新对象时,系统要完成两个步骤: 1. 为对象分配内存,即对象获得一个用来存放其实例变量的内存块; 2. 自动调用 init 方法,让该对象处于可用状态。
  • 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. 总结: 3. 协议: 正式协议是一个命名的方法列表。 采用协议意味着必须实现该协议的所有方法。否则,编译器会发出警告。 正式协议就像 JAVA 中的接口一样。 声明协议: @protocal NSCopying -(id) copywithzone:(NSZone *) zone; // 方法列表 @end 采用协议: @interface Car:NSObject <NSCopying,NSCoding> // 中括号中是要实现的协议列表 {// 实例变量列表 } // 方法列表 @end 在 objective-c 2.0 中,有新特性: @optional, @required
  • 30. Q & A
  • 31.