iOS编程新手的一些问题(2)

hikui posted @ 2012年4月15日 12:03 in iOS开发 , 1738 阅读

2、Cocoa collections的问题。

NSArray, NSDictionary, NSSet,以及这些类型的Mutable形式类型有一个共同点,就是只能接受对象作为Value。结构体和基本类型是不能保存进collections的。所以诸如

    NSMutableArray *array = [[NSMutableArray alloc]init];
    int i = 1;
    NSInteger nsi = 2;
    CGRect rect = CGRectMake(0, 0, 0, 0);
    [array addObject:1];
    [array addObject:nsi];
    [array addObject:rect];

都是不正确的。int是基本类型,CGRect是结构体,所以不能被collections接受。

这里要注意的就是NSInteger声明的变量不是对象,它只是int或者long的别名。NSInteger的定义是这样的:

 

#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
#else
typedef int NSInteger;
#endif

另外的CGFloat也是一样的。

所以要将这种东西存储到collections里面,需要包装成对象。比如数字类型的东西都包装成NSNumber,CG等类型的结构体包装成NSValue,然后存入collections里面,读取的时候,调用相应的xxValue方法就能还原成基本类型。

3、使用Delegate模式需要小心:

我上次调试别人的程序时,几乎所有的崩溃都是因为使用delegate模式不当造成的。Java、C#使用delegate没有什么困难,而Objective-C里面,在没有ARC的情况下,需要手动管理内存,问题就出现了。

现在有A、B两个对象,A作为B的delegate,即B.delegate = A。假设B需要花很长的时间做完工作,做完工作之后调用A实现的delegate方法,而此时A已经被销毁了。这时B.delegate依旧指向A原来的地址而不是nil,B就会向原来地址的已经被销毁的对象发送消息。这时程序就崩溃了。

所以当B.delegate = A的情况下,在A会被销毁的时候,必须设置B.delegate = nil。这样,即便B要调用delegate方法时,A已经被销毁,B也是像nil发送消息。在Objective -C中,这样是完全合法的,并且会什么都不做。

很多时候,给B设置delegate的工作是在A内部做的,即在A的某个方法里面,有B.delegate = self这样的语句。所以A的dealloc方法里面需要增加

if (B.delegate==self){
    B.delegate = nil;
}

这样的语句。

4、viewDidUnload需要做事:

很多人在写代码的时候,总是忽略viewDidUnload这个方法。但是在使用xcode生成的ViewController模板里面又一直会看到viewDidUnload这个方法。模板里面明显有两行注释:

 

// Release any retained subviews of the main view.

// e.g. self.myOutlet = nil;

这是很重要的信息。它的意思是说,如果你在ViewController的对象里面retain了一些subview,就需要在这里将他们释放掉。

如果不写的话,乍看程序不会有什么问题,既不报错也不崩溃。但是在系统内存紧缺时,你的程序被系统kill的概率就非常的高了。

iOS在内存紧缺时发送memory warning。收到这个信号后,你的程序会自动调用现在还活着的ViewController的didReceiveMemoryWarning方法,并且如果你的ViewController并不在当前显示状态(可能在NavigationController栈里面),就会销毁这个ViewController.view。此时,view是retain过它的subview的,而如果viewController也retain过里面某些subview,那么这些subview的retainCount==2。系统销毁view时,对里面所有的subview进行release,此时被ViewController retain过的subview的retainCount==1,系统无法销毁。接下来,系统调用ViewController的viewDidUnload,如果此时你做了self.someSubview = nil这件事,那么对这个subview来说,又进行了release(由于点表达式是setter方法,参加前篇),此时retainCount==0,就可以被销毁了。如果什么都没做,那么这个Subview就不会被销毁,额外增加了内存负担,就提高被系统杀死的风险了。

这里另外要注意的是,写self.someSubview = nil是在someSubview为ViewController的@property(retain)时才能用的,如果不是property,而又在程序里retain了,那么viewDidUnload必须写成:

 

[someSubview release];
someSubview = nil;

切不可直接写someSubview = nil,否则就内存泄漏了。

創用 CC 授權條款
本著作係採用創用 CC 姓名標示 2.0 通用版 授權條款授權.

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter