新手开发IOS的疑惑,待补充
1.Prefix.pch 是做什么用的?
是一个加快编译速度的工具。只有永远不会变化或很少发生变化的头文件才能被添加到前缀文件中。这样做可以使框架的代码提前编译,并对所有类可见。但是,如果添加到前缀文件中的头文件发生变化,那么所有的代码会被重新编译,这也是为什么只能向前缀文件添加不变文件的原因。
2.if((self = [super init])) 为什么会这么写?
- (id) init { if((self = [super init])) { //do init stuff here ... } return self; }
在 self = [super init] 的调用中,self被赋值为向父对象发送 init 消息后的返回值。如果你之前是一名C++程序员,看到这一幕一定会感到痛苦万分。请不必太过沮丧。这行代码表示:在Objective-C中,我们必须手动调用父类的 init 方法,改操作不会自动完成。我们之所以用 self 来接受返回值,是为了防止返回值为 nil 的情况发生。
如果你无法很好的理解Objective-C程序员调用[super init]的方式,另一种方法也许能令你比较容易接受。这种方式基本上和上面的方法一样,但它也是有别于传统的写法的:
- (id) init { self = [super init]; if(self != nil) { //do init stuff here ... } return self; }
3.IOS目前版本的内存管理差异
iOS6.0以前版本
UIViewController 增加了 viewDidUnload 方法。该方法和 viewDIdLoad 相配对。当系统内存不足时,首先 UIViewController 的 didReceiveMemoryWarining 方法会被调用,而 didReceiveMemoryWarining 会判断当前 ViewController 的 view 是否显示在 window 上,如果没有显示在 window 上,则 didReceiveMemoryWarining 会自动将 viewcontroller 的view 以及其所有子 view全部销毁,然后调用 viewcontroller 的 viewdidunload 方法。如果当前 UIViewController 的 view 显示在 window 上,则不销毁该 viewcontroller 的 view,当然,viewDidunload 也不会被调用了。
收到内存警告:调用 didReceiveMemoryWarning 内调用 super 的 didReceiveMemoryWarning 会将 controller 的 view 进行释放。所以我们不能将controller的view再次释放。
处理方法:
-(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning];//如没有显示在window上,会自动将self.view释放。 // ios6.0以前,不用在此做处理,self.view释放之后,会调用下面的viewDidUnload函数,在viewDidUnload函数中做处理就可以了。 } -(void)viewDidUnload { // Release any retained subviews of the main view.不包含self.view [super viewDidUnload]; //处理一些内存和资源问题。 }
但是到了IOS 6.0之后,这里又有所变化,IOS 6.0内存警告的 viewDidUnload 被屏蔽,即又回到了IOS 6.0以前版本时期的内存管理方式。
收到内存警告:调用 didReceiveMemoryWarning 内调用 super 的 didReceiveMemoryWarning 调只是释放 controller 的 resouse,不会释放view。
处理方法:
-(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning];//即使没有显示在window上,也不会自动的将self.view释放。 // Add code to clean up any of your own resources that are no longer necessary. // 此处做兼容处理需要加上ios6.0的宏开关,保证是在6.0下使用的,6.0以前屏蔽以下代码,否则会在下面使用self.view时自动加载viewDidLoad if ([self.view window] == nil)// 是否是正在使用的视图 { // Add code to preserve data stored in the views that might be // needed later. // Add code to clean up other strong references to the view in // the view hierarchy. self.view = nil;// 目的是再次进入时能够重新加载调用viewDidLoad函数。 } }
4.消息调度 @selector
看到 @selector(...) 语句的时候可能觉得有些陌生,这在 Objective-C 中用来指定某个特定方法。关键在于,绝不能忘记函数后面的冒号!冒号告诉 Objective-C:“去找一个名为XXX的方
法,这个方法有且只有一个参数”。如果忘记写冒号,编译器还是可以通过的,但是程序一运行就会发生崩溃。在 Debugger Console 窗口中,你会看到这样的错误日志:“unrecoginized
selector sent to instance...”。
@selector(...) 中的冒号个数一定要与所指定的方法参数个数相同。例如:
- (void) example:(ccTime)delta sender:(id)sender flag:(bool)aBool
那么,对应的@selector语句就应该是:
@selector(example:sender:flag:);
不论是在调度消息时还是在其他情况下使用 @selector(...), 都需要注意一个很重要的问题:在默认情况下,如果方法名不存在,编译器并不会报错;但是,一旦程序运行时调用用了指向不存在的方法的 @selector 语句,应用程序就会立即崩溃。由于这个调用是在内部完成的,所以很难找到问题所在。好在,xcode可以设置来强制编译器报错。
如图:
5.#import与@class的区别
1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
2.在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
3.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
4.如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.