欢迎大家参与 " 爱疯了 " 技术交流分享




                      分享人:李航 ( 酷酷 )

            h ttp ://we ib o .c o m /lid ao h an g
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
。
2.Objective-C 与 C++

每个 Objective-C 对象都隐藏着一个数据结构,它的第一个成员
变量或者说实例变量是 "isa" 指针。 isa 指针指向的是对象的
类,这个类也是一个对象,有自己的权限,是根据类的定义编译
而来的。类对象负责维护一个方法调度表,该表实际上是由指向
类方法的指针组成的。类对象中还保留一个超类的指针,该指针
又有自己的方法调度表和超类。 isa 指针对消息分发机制和
cocoa 对象的动态能力很重要。

C++ 与 Objective-C 最大的区别在于分配方法的机制不同, C++
是基于虚拟表机制确定虚函数调用什么代码,而 Objective-C
使用运行时,函数进入各种类结构中查找相应的代码以供调用。
这么一比,很明显 C++ 的效率要高的多,正因如此,我们要明
确的是, Objective-C 牺牲了一定的速度和安全,换来了灵活
和便捷,这是一种权衡利弊的做法。                     3
3. 常见语法说明
1. 头文件引用使用 #import “ 文件名”或者 #import < 文
件名 > 的形式以确保每个头文件仅被包含一次 。
2. 类声明以 @interface 类名 : 继承类 开头,以 @end 结尾,
类实现以 @implementation 类名 开头,以 @end 结尾。
3. 实例方法,即成员方法,在方法名前面添加一个减号 (-) ;类
方法,在方法名前面添加一个加号 (+) 。

4. 类方法的调用格式为 [ 类名 类方法 ] ,成员方法调用格式
为 [ 实例名 实例方法 ] ,这种模式在 ObjC 中被称为消息机
制, [ 对象 消息 ] 即给对象发送了一个消息,产生的效果就
是该对象调用了该类中定义的对应的实例方法 。
5. 类属性 : N S S trin g * aS trin g ;
6. 协议
@protocol IQuery
-(void) Query:(NSString*) sql;
@end                                4
头文件:
#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


                                              5
实现类:
@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
调用该类:
in t m ain (in t arg c , c o n s t c h ar * arg v[ ] ) {
    N S Au to re le as e Po o l * p o o l = [ [ N S Au to re le as e Po o l allo c ] in it] ;

      Me m Fo o * m yMe m = [ [ Me m F o o allo c ] in it:5:@ "h e llo "] ;

      [ m yMe m re le as e ] ;

}                                                                                               6
4. 属性的介绍与使用:
@property 类型 名字
属性主要分为三类:
1. 读写属性( readwrite / readonly )
2. Setter 属性 ( assign / retain / copy )
3. 原子属性 ( atomicity/nonatomic )
    如果属性是对象类型,你需要使用 retain,assign,copy 参
数,表示 setter 方法内部实现的时候,持有对象的方式。其中
retain 就是增加引用计数,强引用类型。 assign 就是变量的直
接赋值,弱引用类型,也是默认值。 copy 就是把 setter 的参数
复制一遍,再赋给成员变量。 如果你不给出持有对象的方式,
编译器就会给出警告。

  原子属性中, atomic 是默认值,表示属性是原子的,支持
多线程并发访问(在 setter 实现中加入了同步锁),后者是非
原子的,适合在非多线程环境中提升效率,没有加入同步锁。
                                      7
示例代码如下:
#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;


                                                     8
5. 重载父类初始化方法:

@interface MemFoo: NSObject
{
    int x;
    NSString* name;
}
@property int x;
@property (copy) NSString* name;
-(MemFoo*)init:(int) n:(NSString*)str; //重载 NSObject
类初始化方法

@end


                                                 9
@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
in t m ain (in t arg c , c o n s t c h ar * arg v[ ] ) {
    N S Au to re le as e Po o l * p o o l = [ [ N S Au to re le as e Po o l allo c ] in it] ;

    Me m Fo o * m yMe m = [ [ Me m F o o allo c ] in it:5:@ "h e llo "] ;
    [ m yMe m au to re le as e ] ;
    N S Lo g (@ "00000000 x is = % x, n am e is = % @ ",[ m yMe m x] ,[ m yMe m n am e ] );
    [ p o o l d rain ] ;
     re tu rn 0;                                                                     10
}
6. 字符串类各种操作方法
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);
                                                                        11
7. 数字类的各种操作方法
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");                                12
8. 集合类的各种操作方法
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);                           13
9. 文件类的各种操作方法
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!");
}

                                                                             14
10. 协议
正式协议 (p ro to c al)
其实就是非正式协议 (in te rfac e ) 换了一种写法而已,看上去更正规一些,语义上更强
烈一些:要求采用该协议的类,”必须”实现协议中约定的方法。但是比较娱乐的是
,即使是号称正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。
(当然正式协议也有它存在的意义,后面会提到)
这里我们定义一个 IQ u e ry 的协议
协议:
@ p ro to c o l IQ u e ry
- (vo id ) Q u e ry:(N S S trin g * ) s q l;
@ e nd
头文件类:
@ in te rfac e D B Q u e ry : N S O b j c t< IQ u e ry> {
                                          e
}
@ e nd
实现类:
@ im p le m e n tatio n D B Q u e ry
- (vo id ) Q u e ry:(N S S trin g * )s q l
{
N S Lo g (@ ”Q u e ry is c alle d . s q l:% @ ”,s q l);
}
@ e nd                                                    15
11. 内存管理
移动开发的特点:资源的有限性。作为手持设备, iphone 的内
存与传统的 PC 不可同日而语,这就要求我们在开发 IOS 程序的
过程中,首要也是最重要的任务就是解决内存释放问题,本文将
在网络上搜集的关于内存管理的经验予以分享。
    开发 iPhone 应用程序并不难,基本上就是三个词 -
“memory, memory, memory” 。 iPhone OS 对内存的要求很严
格,有 memory leak ,杀掉; 内存使用超限额,杀掉。一个经
过测试的程序,在使用过程中 90% 以上的崩溃都是内存问题造成
的。在这里简单总结一下 Objective-C 内存管理。
一、基本概念
   Objective-C 的内存管理基于引用计数 (Reference Count)
这种非常常用的技术。简单讲,如果要使用一个对象,并希望确
保在使用期间对象不被释放,需要通过函数调用来取得“所有权
”,使用结束后再调用 函数释放“所有权”。“所有权”的获
得和释放,对应引用计数的增加和减少,为正数时代表对象还有
引用,为零时代表可以释放。                              16
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 来处理。
                                                17
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
                                       18
也就是说, retain 是指针拷贝, copy 是内容拷贝。
11. 内存管理
内存管理算是学习一门语言时,比较难但是最重要的一部分。
object - c 中的 Foundation 框架带入了引用计数这一概念和思
想来管理内存。极大的减轻了程序员内存管理的负担,你不必再
那么小心翼翼。
   引用计数的概念如下,创建对象时,将它的引用计数设置为
1 ,每次必须保持该对象时,就发送一条 retain 消息,使其引用
计数加 1 。 Foundation 框架提供的其他一些方法也可以增加对
象的引用计数,例如,把对象添加到数组中。
   不需要对象时,可以通过发送一条 release 消息,使对象的
引用计数减 1 。
   当对象的引用计数到 0 时,系统就知道不再需要这个对象了
,因此系统会释放( deallocates )它的内存。这是通过一条
dealloc 消息而实现的。
首先,我们看下面的代码示例:

                                     19
11. 内存管理
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.
                                                                                20
可变字符串对象 str2 被设置为常量字符串 @"str2" 的副本。通过发送 stringWithstring 消息来
11. 内存管理
自动释放池,在 O b j c tive - C 模块中,发挥着重要作用,能够帮助我们清理很多内存。但是它也
                e
不是万能的,也必须要合理小心的使用。
本文通过一个示例代码,来介绍下自动释放池的用法和注意事项。
  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]; //必须要自己主动释放一次
 运行结果如下所示:

201 1 - 03- 22   23:39:1 8.1 85   Me m o ryTe s t[ 478:a0f]   aaaaa   re tain c o u n t: 1
201 1 - 03- 22   23:39:1 8.1 87   Me m o ryTe s t[ 478:a0f]   bbbbb    re tain c o u n t: 1
201 1 - 03- 22   23:39:1 8.1 88   Me m o ryTe s t[ 478:a0f]   ccccc   re tain c o u n t: 2
201 1 - 03- 22   23:39:1 8.1 88   Me m o ryTe s t[ 478:a0f]   ddddd    re tain c o u n t: 1
                                                                                              21
所以,除了依赖于自动释放池外,对于额外的增加引用,必须由自己去亲自释放。
12. 总结:
与 C 语言相比要注意的地方:
1. 文件介绍: Objective-C 也使用头文件 (header files) ,后缀为 .h, 但使用
.m (即 message, 其他面向对象编程语言也叫 method ),作为源文件的后缀。
在 O b j c tive - C 中使用# import<>, 而不使用# include<> ,# import 可以保证头文
       e
件只被包含一次。
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. 方括号内第一项是对象,其余部分是你需要对象执行的操作。                                  22
3. 在 objective-c 中通知对象执行某种操作,称为发送消息。(也叫调用方法)
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...>
// 类名(类别名):父类 < 协议 >                                          23
总结:
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 是不可变的,即一旦创建完成,就不能通过删除字符或添加字符的方式来改变它;




                                                              24
总结:
而 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: 自动释放内存池。




                                                        25
总结:
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 中,才会被自
                                                           26
动释放。
总结:
内存管理黄金准则:
只有通过 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 方法,让该对象处于可用状态。


                                                                   27
总结:
3. 类别:
类别( category )是一种为现有的类添加新方法的方式。类别的声明:
@interface NSString (NumberConvenience) // 类名 (类别名)
-(NSNumber) lengthAsNumber; // 扩充方法声明
@end
使用时使用原来的类名,就可以调用他的所有类别中的方法。
类别的局限性:
1. 不能向类中添加新的实例变量;
2. 在类别中的方法若与类中现有的方法重名,则类中的方法不可用,被类别中的新方法取代。
类别的作用:
1. 将类的实现分散到多个文件或框架中;
2. 创建对私有方法的前向引用;
【 Cocoa 中没有真正的私有方法,则实现私有方法类似功能的方法为:
先在类别中声明方法;然后到现有类的实现中实现该方法。
这样这个类中的其他方法可以使用该方法,而其他外部的类就不会知道该方法的存在了。】
3. 向对象添加非正式协议。
【创建一个 NSObject 的类别称为创建一个非正式协议。】
委托 delegate 是一种对象,另一个类的对象会要求委托对象执行它的某些操作。
受委托对象在某个时间(某个事件触发)时,会自动通知委托对象执行委托方法。
选择器: @selector () : 选择器只是一个方法名称,但它以 objective-c 运行时使用的特殊方式
编码,以快速执行查询。圆括号中的内容是方法名。
所以 Car 类的 setEngine: 方法的选择器是: @selector ( setEngine:
受委托对象如何知道其委托对象是否能处理它(受委托对象)发送给它(委托对象)的消息?
                                                        28
通过选择器,受委托对象先检查委托对象,询问其是否能响应该选择器。如果能,则向它发送消息
总结:
3. 协议:
正式协议是一个命名的方法列表。
采用协议意味着必须实现该协议的所有方法。否则,编译器会发出警告。
正式协议就像 JAVA 中的接口一样。
声明协议:
@protocal NSCopying
-(id) copywithzone:(NSZone *) zone; // 方法列表
@end
采用协议:
@interface Car:NSObject <NSCopying,NSCoding> // 中括号中是要实现的协议列表
{// 实例变量列表 }
// 方法列表
@end
在 objective-c 2.0 中,有新特性: @optional, @required




                                                                29
Q & A
Tha nks



          Confidential & Proprietary 2010

ios分享

  • 1.
    欢迎大家参与 " 爱疯了" 技术交流分享 分享人:李航 ( 酷酷 ) h ttp ://we ib o .c o m /lid ao h an g
  • 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++ : 不支持操作符重载,模版和多重继承 2 。
  • 3.
    2.Objective-C 与 C++ 每个Objective-C 对象都隐藏着一个数据结构,它的第一个成员 变量或者说实例变量是 "isa" 指针。 isa 指针指向的是对象的 类,这个类也是一个对象,有自己的权限,是根据类的定义编译 而来的。类对象负责维护一个方法调度表,该表实际上是由指向 类方法的指针组成的。类对象中还保留一个超类的指针,该指针 又有自己的方法调度表和超类。 isa 指针对消息分发机制和 cocoa 对象的动态能力很重要。 C++ 与 Objective-C 最大的区别在于分配方法的机制不同, C++ 是基于虚拟表机制确定虚函数调用什么代码,而 Objective-C 使用运行时,函数进入各种类结构中查找相应的代码以供调用。 这么一比,很明显 C++ 的效率要高的多,正因如此,我们要明 确的是, Objective-C 牺牲了一定的速度和安全,换来了灵活 和便捷,这是一种权衡利弊的做法。 3
  • 4.
    3. 常见语法说明 1. 头文件引用使用#import “ 文件名”或者 #import < 文 件名 > 的形式以确保每个头文件仅被包含一次 。 2. 类声明以 @interface 类名 : 继承类 开头,以 @end 结尾, 类实现以 @implementation 类名 开头,以 @end 结尾。 3. 实例方法,即成员方法,在方法名前面添加一个减号 (-) ;类 方法,在方法名前面添加一个加号 (+) 。 4. 类方法的调用格式为 [ 类名 类方法 ] ,成员方法调用格式 为 [ 实例名 实例方法 ] ,这种模式在 ObjC 中被称为消息机 制, [ 对象 消息 ] 即给对象发送了一个消息,产生的效果就 是该对象调用了该类中定义的对应的实例方法 。 5. 类属性 : N S S trin g * aS trin g ; 6. 协议 @protocol IQuery -(void) Query:(NSString*) sql; @end 4
  • 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 5
  • 6.
    实现类: @implementation MemFoo @synthesize x; @synthesizename; //重载的实现 -(MemFoo*)init:(int)n:(NSString*)str { self=[super init]; //先使用父类方法进行初始化 if (self!=NULL) { self.x=n; self.name=str; } return self; } @end 调用该类: in t m ain (in t arg c , c o n s t c h ar * arg v[ ] ) { N S Au to re le as e Po o l * p o o l = [ [ N S Au to re le as e Po o l allo c ] in it] ; Me m Fo o * m yMe m = [ [ Me m F o o allo c ] in it:5:@ "h e llo "] ; [ m yMe m re le as e ] ; } 6
  • 7.
    4. 属性的介绍与使用: @property 类型名字 属性主要分为三类: 1. 读写属性( readwrite / readonly ) 2. Setter 属性 ( assign / retain / copy ) 3. 原子属性 ( atomicity/nonatomic ) 如果属性是对象类型,你需要使用 retain,assign,copy 参 数,表示 setter 方法内部实现的时候,持有对象的方式。其中 retain 就是增加引用计数,强引用类型。 assign 就是变量的直 接赋值,弱引用类型,也是默认值。 copy 就是把 setter 的参数 复制一遍,再赋给成员变量。 如果你不给出持有对象的方式, 编译器就会给出警告。 原子属性中, atomic 是默认值,表示属性是原子的,支持 多线程并发访问(在 setter 实现中加入了同步锁),后者是非 原子的,适合在非多线程环境中提升效率,没有加入同步锁。 7
  • 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; 8
  • 9.
    5. 重载父类初始化方法: @interface MemFoo:NSObject { int x; NSString* name; } @property int x; @property (copy) NSString* name; -(MemFoo*)init:(int) n:(NSString*)str; //重载 NSObject 类初始化方法 @end 9
  • 10.
    @implementation MemFoo @synthesize x; @synthesizename; //重载的实现 -(MemFoo*)init:(int)n:(NSString*)str { self=[super init]; //先使用父类方法进行初始化 if (self!=NULL) { self.x=n; self.name=str; } return self; } @end in t m ain (in t arg c , c o n s t c h ar * arg v[ ] ) { N S Au to re le as e Po o l * p o o l = [ [ N S Au to re le as e Po o l allo c ] in it] ; Me m Fo o * m yMe m = [ [ Me m F o o allo c ] in it:5:@ "h e llo "] ; [ m yMe m au to re le as e ] ; N S Lo g (@ "00000000 x is = % x, n am e is = % @ ",[ m yMe m x] ,[ m yMe m n am e ] ); [ p o o l d rain ] ; re tu rn 0; 10 }
  • 11.
    6. 字符串类各种操作方法 NSString *str=@"everyday 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); 11
  • 12.
    7. 数字类的各种操作方法 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"); 12
  • 13.
    8. 集合类的各种操作方法 NSMutableArray *weekName=[NSMutableArray arrayWithObjects:@"MM",@"TT",@"WW",nil]; inti=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); 13
  • 14.
    9. 文件类的各种操作方法 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!"); } 14
  • 15.
    10. 协议 正式协议 (pro to c al) 其实就是非正式协议 (in te rfac e ) 换了一种写法而已,看上去更正规一些,语义上更强 烈一些:要求采用该协议的类,”必须”实现协议中约定的方法。但是比较娱乐的是 ,即使是号称正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。 (当然正式协议也有它存在的意义,后面会提到) 这里我们定义一个 IQ u e ry 的协议 协议: @ p ro to c o l IQ u e ry - (vo id ) Q u e ry:(N S S trin g * ) s q l; @ e nd 头文件类: @ in te rfac e D B Q u e ry : N S O b j c t< IQ u e ry> { e } @ e nd 实现类: @ im p le m e n tatio n D B Q u e ry - (vo id ) Q u e ry:(N S S trin g * )s q l { N S Lo g (@ ”Q u e ry is c alle d . s q l:% @ ”,s q l); } @ e nd 15
  • 16.
    11. 内存管理 移动开发的特点:资源的有限性。作为手持设备, iphone的内 存与传统的 PC 不可同日而语,这就要求我们在开发 IOS 程序的 过程中,首要也是最重要的任务就是解决内存释放问题,本文将 在网络上搜集的关于内存管理的经验予以分享。 开发 iPhone 应用程序并不难,基本上就是三个词 - “memory, memory, memory” 。 iPhone OS 对内存的要求很严 格,有 memory leak ,杀掉; 内存使用超限额,杀掉。一个经 过测试的程序,在使用过程中 90% 以上的崩溃都是内存问题造成 的。在这里简单总结一下 Objective-C 内存管理。 一、基本概念 Objective-C 的内存管理基于引用计数 (Reference Count) 这种非常常用的技术。简单讲,如果要使用一个对象,并希望确 保在使用期间对象不被释放,需要通过函数调用来取得“所有权 ”,使用结束后再调用 函数释放“所有权”。“所有权”的获 得和释放,对应引用计数的增加和减少,为正数时代表对象还有 引用,为零时代表可以释放。 16
  • 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 来处理。 17
  • 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 18 也就是说, retain 是指针拷贝, copy 是内容拷贝。
  • 19.
    11. 内存管理 内存管理算是学习一门语言时,比较难但是最重要的一部分。 object -c 中的 Foundation 框架带入了引用计数这一概念和思 想来管理内存。极大的减轻了程序员内存管理的负担,你不必再 那么小心翼翼。 引用计数的概念如下,创建对象时,将它的引用计数设置为 1 ,每次必须保持该对象时,就发送一条 retain 消息,使其引用 计数加 1 。 Foundation 框架提供的其他一些方法也可以增加对 象的引用计数,例如,把对象添加到数组中。 不需要对象时,可以通过发送一条 release 消息,使对象的 引用计数减 1 。 当对象的引用计数到 0 时,系统就知道不再需要这个对象了 ,因此系统会释放( deallocates )它的内存。这是通过一条 dealloc 消息而实现的。 首先,我们看下面的代码示例: 19
  • 20.
    11. 内存管理 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. 20 可变字符串对象 str2 被设置为常量字符串 @"str2" 的副本。通过发送 stringWithstring 消息来
  • 21.
    11. 内存管理 自动释放池,在 Ob j c tive - C 模块中,发挥着重要作用,能够帮助我们清理很多内存。但是它也 e 不是万能的,也必须要合理小心的使用。 本文通过一个示例代码,来介绍下自动释放池的用法和注意事项。 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]; //必须要自己主动释放一次 运行结果如下所示: 201 1 - 03- 22 23:39:1 8.1 85 Me m o ryTe s t[ 478:a0f] aaaaa re tain c o u n t: 1 201 1 - 03- 22 23:39:1 8.1 87 Me m o ryTe s t[ 478:a0f] bbbbb re tain c o u n t: 1 201 1 - 03- 22 23:39:1 8.1 88 Me m o ryTe s t[ 478:a0f] ccccc re tain c o u n t: 2 201 1 - 03- 22 23:39:1 8.1 88 Me m o ryTe s t[ 478:a0f] ddddd re tain c o u n t: 1 21 所以,除了依赖于自动释放池外,对于额外的增加引用,必须由自己去亲自释放。
  • 22.
    12. 总结: 与 C语言相比要注意的地方: 1. 文件介绍: Objective-C 也使用头文件 (header files) ,后缀为 .h, 但使用 .m (即 message, 其他面向对象编程语言也叫 method ),作为源文件的后缀。 在 O b j c tive - C 中使用# import<>, 而不使用# include<> ,# import 可以保证头文 e 件只被包含一次。 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. 方括号内第一项是对象,其余部分是你需要对象执行的操作。 22 3. 在 objective-c 中通知对象执行某种操作,称为发送消息。(也叫调用方法)
  • 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...> // 类名(类别名):父类 < 协议 > 23
  • 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 是不可变的,即一旦创建完成,就不能通过删除字符或添加字符的方式来改变它; 24
  • 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: 自动释放内存池。 25
  • 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 中,才会被自 26 动释放。
  • 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 方法,让该对象处于可用状态。 27
  • 28.
    总结: 3. 类别: 类别( category)是一种为现有的类添加新方法的方式。类别的声明: @interface NSString (NumberConvenience) // 类名 (类别名) -(NSNumber) lengthAsNumber; // 扩充方法声明 @end 使用时使用原来的类名,就可以调用他的所有类别中的方法。 类别的局限性: 1. 不能向类中添加新的实例变量; 2. 在类别中的方法若与类中现有的方法重名,则类中的方法不可用,被类别中的新方法取代。 类别的作用: 1. 将类的实现分散到多个文件或框架中; 2. 创建对私有方法的前向引用; 【 Cocoa 中没有真正的私有方法,则实现私有方法类似功能的方法为: 先在类别中声明方法;然后到现有类的实现中实现该方法。 这样这个类中的其他方法可以使用该方法,而其他外部的类就不会知道该方法的存在了。】 3. 向对象添加非正式协议。 【创建一个 NSObject 的类别称为创建一个非正式协议。】 委托 delegate 是一种对象,另一个类的对象会要求委托对象执行它的某些操作。 受委托对象在某个时间(某个事件触发)时,会自动通知委托对象执行委托方法。 选择器: @selector () : 选择器只是一个方法名称,但它以 objective-c 运行时使用的特殊方式 编码,以快速执行查询。圆括号中的内容是方法名。 所以 Car 类的 setEngine: 方法的选择器是: @selector ( setEngine: 受委托对象如何知道其委托对象是否能处理它(受委托对象)发送给它(委托对象)的消息? 28 通过选择器,受委托对象先检查委托对象,询问其是否能响应该选择器。如果能,则向它发送消息
  • 29.
    总结: 3. 协议: 正式协议是一个命名的方法列表。 采用协议意味着必须实现该协议的所有方法。否则,编译器会发出警告。 正式协议就像 JAVA中的接口一样。 声明协议: @protocal NSCopying -(id) copywithzone:(NSZone *) zone; // 方法列表 @end 采用协议: @interface Car:NSObject <NSCopying,NSCoding> // 中括号中是要实现的协议列表 {// 实例变量列表 } // 方法列表 @end 在 objective-c 2.0 中,有新特性: @optional, @required 29
  • 30.
  • 31.
    Tha nks Confidential & Proprietary 2010