iOS技术问答

1.@property中有哪些属性关键字

strong

weak 主要使用在代理,UI控件

copy 拷贝一个对象引用计数+1

assign 默认assign

atomic 默认线程安全

nonatomic

getter

setter

readwrite

readonly

writeonly

2.weak属性需要在dealloc中置nil么?

不需要。在ARC环境无论是强指针还是弱指针都无需在 dealloc 设置为 nil , ARC 会自动帮我们处理

3.ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

assign,atomic,readwrite

4.用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

copy此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。

5.@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

如果指定了成员变量的名称,会生成一个指定的名称的成员变量,
如果这个成员已经存在了就不再生成了.
如果是 @synthesize foo;还会生成一个名称为foo的成员变量,也就是说:如果没有指定成员变量的名称会自动生成一个属性同名的成员变量,
如果是 @synthesize foo = _foo;就不会生成成员变量了.

不会。

6.objc中向一个nil对象发送消息将会发生什么?

如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

7.objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

objc_msgSend()是[obj foo]的具体实现。

8.什么时候会报unrecognized selector的异常?

当调用该对象上某个方法,而该对象上没有实现这个方法的时候.(可以通过“消息转发”进行解)

9.一个objc对象如何进行内存布局?(考虑有父类的情况)


10.objc对象的isa的指针指向什么?有什么作用?

是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

11.runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)

每一个类对象中都一个对象方法列表(对象方法缓存)
类方法列表是存放在类对象中isa指针指向的元类对象中(类方法缓存)
方法列表中每个方法结构体中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.
当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找
当我们发送一个消息给一个类时,这条消息会在类的Meta Class对象的方法列表里查找

12.Load方法特点

runtimed的时候只调用一次

父类的load在子类之前调用,主类的load在分类之前调用

父类实现了load,子类没有实现,子类不会去调用父类的load

可以用来做全局性的Method Swizzle

13.initialize方法特点

懒加载方式,在实例化的时候只调用一次

和普通方法一样,会继承父类的initialize方法

分类实现了initialize方法会覆盖主类的initialize

14.Category

在不知道源代码的情况下给类添加方法,多个分类有相同的方法会覆盖,覆盖顺序不确定

分模块添加Category可以减少主类的文件大小,

编译期不能添加属性,runtime的时候可以使用associated object来添加

15.Extension

必须在源码当中添加

在implementiaon区间内实现

用来添加私有属性和方法,可以改变属性的访问特性,如在.h文件中暴露为readonly,而在extension中修改为readwrite,则在.m文件中能使用self来访问。

16.如何给全局静态对象变量初始化

重载initialize方法

使用__attribute__((constructor))

17.synthesize和dynamic

现代OC的property会自动生成getter和setter,并关联ivar不需要synthesize

需要手动synthesize的情况:

*readwriter需要重写getter和setter

*readonly自己实现getter

*protocoll里面有属性,编译器不会自动synthesize

*重载父类中的属性

*使用dynamic,显示不希望编译器生成getter和setter

18.用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
最后的这个参数类似于property的属性设置,有如下几个
OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY
可以根据我们的具体需要进行使用,无论arc和mrc的情况。就像平时的规则一样。

19.objc中的类方法和实例方法有什么本质区别和联系?

一个类方法只开辟一块内存空间,实例方法根据需要开辟多块内存空间

类方法里面不能访问self指针,实例方法可以,self是自身

类方法和实例方法访问方式不同,类方法直接用类名字加方法名即可访问

类方法不能访问成员变量

类方法不能直接调用对象方法

20._objc_msgForward函数是做什么的,直接调用它将会发生什么?

当对象没有实现某个方法 ,会调用这个函数进行方法转发。某方法对应的IMP没找到,会返回这个函数的IMP去执行)
1.调用resolveInstanceMethod:方法,允许用户在此时为该Class动态添加实现。如果有实现了,则调用并返回。如果仍没实现,继续下面的动作。
2.调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接转发给它。如果返回了nil,继续下面的动作。
3.调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。
4.调用forwardInvocation:方法,将地3步获取到的方法签名包装成Invocation传入,如何处理就在这里面了。

如果直接调用这个方法,就算实现了想调用的方法,也不会被调用,会直接走消息转发步骤。

21.runtime如何实现weak变量的自动置nil?

runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

22.BAD_ACCESS在什么情况下出现?点击打开链接

访问了野指针,比如对一个已经释放的对象执行了release、访问已经释放对象的成员变量或者发消息。
死循环

23.苹果是如何实现autoreleasepool的?

点击打开链接

24.NSArray的copy方法和NSMutableArray的copy方法有什么不同?

因为NSArray是不可变类型数组,所以为了节省内存,copy后的新指针也会指向同一内存地址。如果copy的是NSMutableArray,那么你就会发现新拷贝的数组的地址与原数组地址不一样了。同样适用于NSString与NSMutableString。

他们里面存储的对象的地址都不变,所以copy不拷贝数组中对象的地址。

 

    NSObject *obj1 = [[NSObject alloc] init];
    
    NSArray *array1 = [NSArray arrayWithObject:obj1];
    NSArray *array2 = [array1 copy];
    
    NSMutableArray *array3 = [NSMutableArray arrayWithObject:obj1];
    NSMutableArray *array4 = [array3 copy];
    
    NSLog(@"%p %p",array1,array2);
    NSLog(@"%p %p",array3,array4);

    NSLog(@"%p %p",[array1 objectAtIndex:0],[array2 objectAtIndex:0]);
    NSLog(@"%p %p",[array3 objectAtIndex:0],[array4 objectAtIndex:0]);
25.什么样的block会有循环引用?如何打破循环引用?

原因:
block对象持有self对象,self对象持有block对象时会产生循环引用。所以一般在栈上的block不会产生,即使在block中使用到了self,原因是self没有持有这个block对象。系统级的block:UIView animation,NSArray enumeration一般都在栈上使用,不会全局保存,所以不会产生循环引用。

解决:
1.使用weak self来解决循环引用的问题,但为了避免block中使用的对象提前被释放掉,在block中可以创建一个在栈上的强引用strong self,来避免这个问题。
2.使用完block后置nil,来释放block里面的对象。

点击打开链接

26.什么是dispatch_barrier_async函数?点击打开链接

dispatch_barrier_async函数的作用与barrier的意思相同,在进程管理中起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行,该函数需要同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一起使用



下方是我的订阅号,会收集各种问答并每天发布,欢迎关注iOS技术内幕。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值