一些小知识点(持续更新)

有两年没有开发iOS了,最近又开始接触iOS开发,发现好多旧知识忘记了,好多新知识还不知道。

最近正在学习中,一些心得做下memo,,也可以和大家分享一下。

初始化方法的返回值类型(类名,id,instancetype)

初始化方法的返回值一般设成id。为什么呢?为什么不设成类名呢?如果你设成类名,子类就不好处理了。比如说子类想覆盖父类的初始化方法,但想返回自己的类型,就不好处理了。所以一般返回id类型。

但是id类型不是type safe的。比如说,NSString *str = [NSArray array]; 编译器是检查不是来的,等到运行的时候就会崩溃的。

后来LLVM编译器出来之后,建议使用instancetype来代替id。凡是返回值是instancetype的方法,编译器都会检查返回值,如果没有返回本类或者子类,都会报编译错误。

NSInteger和int,long

NSInteger类型可以代表一个int类型或者一个long类型,我们推荐使用NSInteger,是因为它会根据手机的处理器来决定到底用int还是long,如果处理器是32位的,那么就用32位的int,如果处理器是64位的,那么就用64位的long。从A7处理器(iPhone 5S)开始,苹果开始采用64位的处理器。

iOS中的单例模式

从iOS4.0开始,GCD横空出世,不仅方便了多线程开发,也引入了一个适合实现单例模式的函数dispatch_once。一下是具体代码:

+ (instancetype)sharedInstance {static MyClass *shared = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{shared = [[self alloc] init];});return shared;}onceToken是一个检查代码块是否调用过的一个谓词。

dispatch_once不仅能保证代码只调用一次,还是线程安全的,所以就不需要用@synchronized了。确实很方便。

关于self.name和_name的区别

name是属性,通过self.name来调用,调用的是get方法,可以在类外使用。

_name是成员变量,只能在.m文件中使用。

一般来说,.m文件中推荐使用_name。因为使用self.name有时候会带来不必要的麻烦。举个例子:

代码1

self.name = [[NSString alloc] init];代码2

_name = [[NSString alloc] init];self.name = @"name";关于_name的引用计数,代码2是正常的,引用计数为1,代码1时不正常的,引用计数是2。

我们来分析一下:

self.name = 会调用set方法,set方法如下:

– (void)setName:(NSString *)name {if (_name != name) {[_name release];_name = [name retain];}}代码1,alloc了引用计数+1,调用set方法,[_name release]的时候_name还是nil,所以不起作用,最后有retain了,引用计数变为2。

代码2,alloc了引用计数+1,调用set方法,[_name release]的时候_name还是不为nil,所以起了作用,所以,最后引用计数还是为1。

所以,代码1是会造成内存泄漏的。

关于ARC中的strong和copy

@property (copy, nonatomic) NSString *copyName;@property (strong, nonatomic) NSString *strongName;上面的NSString到底用stong还是copy呢?

ARC中的stong其实就是retain,就是引用计数+1。而copy会拷贝一个副本出来。

但是,具体的区别是什么呢?

NSMutableString *name = [NSMutableString stringWithFormat:@"name"];self.copyName = name;self.strongName = name;@"name"存在于堆上面的某个地址中,假设它的地址是0xB1。name存在于栈上面的某个地址中,假设它的地址是0xA1。

同样,我们假设strongName的栈地址是0xA2,copyName的栈地址是0xA3。

strong只是引用计数+1,不会重新分配内存。copy会拷贝副本,所以会重新分配内存,假设分配到0xB2。所以存在以下指向关系:

由于NSMutableString是NSString的子类,子类可以直接赋给父类。

当NSMutableString类型的name在另外一个类里面,通过stringName或copyName所在类的实例来赋值的时候,如果是strongName,会有潜在的风险。因为name和strongName是指向同一块内存的,而name又是可变类型的,所以当外面的name的值变化了,里面的strongName会跟着变化,而我们往往是不希望strongName变化的。要解决此问题,copy就起到了作用,因为copyName又拷贝了一份内存地址,所以和原来的name是相互独立的,不管name改成什么值,copyName永远是@“name”。

所以,如果一个类它的子类有可变类型的,那么我们推荐用copy而不是strong。这样的类有NSArray, NSDictionary, NSSet, NSString, NSData等等。

有人担心从外部传进来的如果不是可变类型的,那么岂不是每次都copy,会存在性能问题?其实ARC会进行判断,如果赋的值时可变类型的,那么就会执行copy,如果赋的值时不可变类型的,那么就不会执行copy,而是让引用计数+1,就和strong一样了。

我知道我不是一个很好的记录者,但我比任何人都喜欢回首自己来时的路,

一些小知识点(持续更新)

相关文章:

你感兴趣的文章:

标签云: