iOS学习笔记

1.在OC中向一个nil对象发送消息会发生什么?
在Objective-C中向nil对象发送消息不会报错,只是在运行不会有任何作用。objc在向一个对象发送消息的时候,runtime是根据对象isa指针找到该对象所属的类,然后在该类和它的父类的方法列表里找方法运行。如果向一个nil对象发送消息的话,在寻找对象的isa指针的时候就返回0地址,所以不会出现任何错误。所以发送给nil的消息返回0(nil);

2.如果@property后面关键字不写,默认是什么?
默认的关键字,OC对象:atomic readwrite strong
基本数据类型:atomic readwrite assign

3.UITableView实现了delegate中的heightForRowAtIndexPath:方法后,rowHeight这个属性的设置将无效。

4.runtime如何实现weak变量自动设置nil
runtime会有一个全局的hash表,用weak指向的对象的地址作为key存入,当对象的引用计数为0的时候,对象要释放的时候runtime就会以对象的地址为key查找到所有存有这个对象的weak属性设置为nil。

5.Block分三种(根据isa指针)
1 _NSConcreteStackBlock 分配在栈上,只用到外部的局部变量、成员属性变量,切没有强指针引用。生命周期由系统管理,一旦返回后就被系统销毁了。
2 _NSConcreteMallocBlock 有强指针引用或copy修饰的成员属性引用的Block会被复制一份到堆上成为MallocBlock,没有强指针引用即销毁(ARC机制),生命周期由程序员控制。
3 _NSConcreteGlobalBlock 没有用到外界变量或只用到全局变量、静态变量,生命周期从创建到应用程序结束为止。

_NSConcreteMallocBlock是持有对象的(Block会对对象进行retain操作)。
_NSConcreteStackBlock和_NSConcreteGlobalBlock不会持有对象。

由于_NSConcreteStackBlock所属的变量域一旦结束,那么该Block就会被销毁。在ARC环境下,编译器会自动的判断,把Block自动的从栈copy到堆上。

  • 手动调用copy
  • Block是函数的返回值
  • Block被强引用
  • 调用系统API传入参数中含有usingBlock的方法

以上4中情况,系统都会默认调用copy方法吧Block复制到堆上。
但是我们自己写的方法把Block作为参数的时候就需要我们手动copy一份到堆上。
copy是把Block从栈上拷到堆上,dispose函数是把堆上的函数在废弃的时候销毁。

ARC环境下,一旦Block赋值就触发copy。copy会让block持有捕捉到的变量(包括自动变量和__block修饰的变量)。
非ARC下,Block被copy时不会持有__block变量,会持有其他变量。

typedef void(^blk)(void);
@interface MyObject : NSObject{
    blk _blk;
}
@end
- (instancetype)init {
    if (self = [super init]) {
        __block id tmp = self;
        _blk = [^{
            NSLog(@"%@",tmp);
        } copy];
    }
    return self;
}

所以这段代码在非arc下不会造成循环引用。在arc会循环引用。

typedef void(^blk)(void);
@interface MyObject : NSObject{
    blk _blk;
}
@end
- (instancetype)init {
    if (self = [super init]) {
        __block id tmp = self;
        _blk = ^{
            NSLog(@"%@",tmp);
            tmp = nil;
        } ;
    }
    return self;
}

这段代码就能在arc下防止循环引用(必须调用blk一次),不过一般arc下都是用__weak来防止循环引用的。

  1. C语言有5种存储域说明符(存储类型)
  • typedef
  • extern
  • static 静态变量存储在数据区中
  • auto 默认,修饰局部变量,自动变量存储在栈中
  • register 存储在寄存器中而不是内存中,不能使用&一元运算符,因为不在内存中,定义了 register 它意味着变量尽可能存储在寄存器中,这还取决于硬件和实现的限制允不允许

7.TCP协议三次握手,握手过程中使用tcp的标志(flag)——SYN(synchronize)和ACK(acknowledgement)
发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。最后,发送端再传回一个带ACK标志的数据包,代表"握手"结束。

8.将写操作放入栅栏快单独执行,读操作并发执行

_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//读取字符串
- (NSString*)someString {
     __block NSString *localSomeString;
     dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
     return localSomeString;
}
//设置字符串
- (void)setSomeString:(NSString*)someString {
     dispatch_barrier_async(_syncQueue, ^{
        _someString = someString;
    });
}

9.iOS中的静态库和动态库
静态库和动态库是相对于编译期和运行期的。静态库在程序编译时会被链接到目标代码中,程序运行不再需要改静态库;而动态库在程序编译时不会链接到目标代码中,只是在程序运行时才被载入。
静态库在链接时,会被完整的复制到可执行文件中,每个APP都会拷贝一份静态库,浪费内存。
动态库只有一份,程序运行时动态地加载到内存中,系统指挥加载一次,多个程序公用一份,节省内存。

10.+load与+initialize方法
+load方法是在runtime组件加载的时候调用的,也就是在main方法之前调用。调用顺序是:父类->子类->分类,系统只会调用一次(可以自己手动调用多次),子类没实现的话不会调用父类的+load方法,分类和类的+load都会调用。
+initialize方法是在向对象发送第一条消息的时候调用的(懒加载),也就是可能永远不调用。调用顺序是:父类->子类,系统可能多次调用,子类没实现会调用父类的initialize方法(+initialize调用是发消息流程),分类的+initialize会覆盖类的+initialize方法。

11.nil、Nil、NULL和NSNull的区别
nil、Nil、NULL本质上是(void*)0,即空指针,即作用完全相同。
NULL是c语言中的空指针,多用于c对象的置空。
nil是OC中的空指针,用于oc对象的置空。
Nil也是OC中的空指针,多用于表示Class的空。
NSNull是oc对象(有内存地址),用于表示一个内容为空的OC对象。

你可能感兴趣的:(iOS学习笔记)