1.风格纠错题
typedef enum {
UserSexMan,
UserSexWoman
}UserSex;
@interface UserModel : NSObject
@property(nonatomic,strong) NSString *name;
@property(nonatomic,assign) int age;
@property(nonatomic,assign) UserSex sex;
- (instancetype)initModelWithUserName:(NSString *)name WithAge:(NSUInteger)age;
- (void)doLogIn;
@end复制代码
答案:
typedef NS_ENUM(NSInteger,UserSex) {
UserSexMan,
UserSexWoman
};
//1.eunm应该替换为NS_OPTIONS或NS_ENUM
@interface UserModel : NSObject
@property(nonatomic,copy) NSString *name;
//2.strong应该改为copy
@property(nonatomic,assign) NSUInteger age;
//3.int应该改为NSUInteger
@property(nonatomic,assign) UserSex sex;
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(UserSex)sex;
//4.指定初始化方法应该包含所有参数
+ (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(UserSex)sex;
//5.应该写一个类方法来初始化
- (void)logIn;
//6.命名规范
@end
复制代码
2.什么时间使用weak关键字,相比assign有什么不同
1.什么情况使用weak
- 在ARC下,为了防止循环引用,比如设置delegate的时候
- 自身已经对它进行一次强引用,没必要再强引用一次的时候,比如自定义IBOutLet控件属性一般也用weak(也可用strong)。
2.不同
- weak和assign一样都表示一种赋值关系,既不保留新值,也不释放旧制,但是weak属性所指的对象被销毁时,指针会自动置为nil。
- weak必须用于OC对象,而assign可以用于基本数据类型(非OC对象)
3.怎么用copy关键字
用途:
- NSString,NSArray,NSDictionary等等经常使用copy关键字,是因为它们有对应的可变类型NSMutableString,NSMutableArray,NSMutableDictionary;
- block也经常用copy关键字
原因:
- copy此特质所表达的所属关系和strong类似,然而设置方法并不保留新值,而是将其拷贝,当所属类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向NSMutableString类型的实例,此时若是不拷贝实例,那么设置完属性之后,字符串的值可能在对象不知情的情况下被人修改,所以,这时应该拷贝一份不可变的NSString,确保对象中的字符串不会无意间被改动。
- block使用copy是从MRC遗留下来的传统,在MRC中,方法内部的block是在栈区的,使用copy可以把它拷贝到堆区,在ARC中写不写都行,对用block使用copy和strong都是一样的。
4.这个写法会出什么问题@property (copy) NSMutableArray *array;
- 对数组进行增删改的时候,程序会因为找不到对应的方法而崩溃,因为copy就是复制一个不可变数组的对象。
- 使用了atomic会严重影响性能。并且atomic并不能保证线程安全,atomic为属性的set,get方法就锁,保证了属性被访问时的线程安全,但是属性所指向的对象仍然可以同时被多个线程同时访问,所以atomic并不能保证线程安全,通常在开发iOS程序是,一般会用nonatimic属性。
5.如何让自己的类用copy修饰符,如何重写带copy关键字的setter?
1.让自己的类支持NSCopying协议
- 声明该类遵从NSCopying协议
- 实现 NSCopying 协议。该协议只有一个方法:- (id)copyWithZone:(NSZone *)zone;
2.如何重写带 copy 关键字的 setter***方法
- (void)setName:(NSString *)name {
//[_name release];
_name = [name copy];
}复制代码
6.@property的本质是什么,ivar,set,get是如何生成并添加到这个类中的
@property 的本质是什么?
@property = ivar + set + get复制代码
ivar,set,get是如何生成并添加到这个类中的
完成属性定义后,编译器会编写访问这些属性所需的方法,此过程叫做自动合成。这个过程由编译器在编译器完成,所以在编译器里看不到合成方法的源代码。除了生成set,get方法外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,一次作为实例变量的名称。此外,也可以在类的实现代码中通过@synthesize语法来制定实例变量的名字。
复制代码
7.@protocol和category中如何使用@property
- 在@protocol中声明属性,只会生成对应的set,get方法声明,我们使用属性的目的,是为了让遵循改协议的对象能实现该属性。
- category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
- objc_setAssociatedObject()
- objc_getAssociatedObject()
8.runtime如何实现weak属性
1.weak属性的特点:
weak此特质表明该属性定义了一种“非拥有关系”,为这种属性设置新值时,设置方法既不保留新值,也不释放旧值,此特质与assign类似,然而当属性所指的对象被销毁时,属性值也会置空。2.runtime如何实现weak的自动置空:
runtime对注册的类会进行布局,对于weak对象会放入一个hash表中。用weak所指向的对象内存地址为key,当此对象的引用计数为0时会dealloc,嫁入weak指向的内存地址为a,那么就以a为键,找到所有以a为键的对象,从而设置为nil。
9.@property都有哪些修饰符
属性可以拥有的特质分为四类
- 原子性:nonatomic和atomic
- 读写权限:weak,assign,strong,copy,retain,unsafe_unretained
- 内存管理语义,readwrite,readonly
- set,get方法
10.weak属性需要在dealloc中置nil么?
不需要,在属性所指的对象被销毁是,属性值也会置空。
11.@synthesizer和@dynamic有什么作用
- @synthesize语义是告诉编译器如果你没有手动实现set,get方法,那么编译器会自动为你加上这两个方法。
- @dynamic语义是告诉编译器不要自动合成set,get方法,这两个方法会由用户手动实现。但如果你没有实现set,get方法,编译的时候不会报错,运行时一旦访问这两个方法,程序就会崩溃。
12.ARC下,不显式指定属性关键字时,默认的关键字有哪些?
- OC对象:atomic readwrite strong
- 基本数据类型(非OC对象): atomic readwrite assign
13.NSString用copy关键字描述,而不用strong描述的原因
- 因为父类指针可以指向子类对象,使用copy的原因是为了让本对象的属性不受外界影响,使用copy无论给我传入一个可变对象还是不可变对象,我本身持有的都是一个 不可变的副本。
- 如果我们使用strong,属性就可能指向一个可变对象,如果这个可变对象在外界被修改了,属性也会受到影响。
14.@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?
实例变量 = 成员变量 = ivar
- 如果@synthesize指定了实例变量的名称,那么就会生成一个指定名称的成员变量
- 如果没有使用@synthesize指定,那么已经存在了_foo的实例变量,就不会再生成了
15. 在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?
- 同时重写了set和get方法
- 重写了只读属性的get方法
- 使用@dynamic
- 在@protocol中定义的属性
- 在category中定义的属性
- 重载了父类的属性
这些情况下都需要你使用@synthesize手动合成ivar,另外还可以用来更改属性对应的成员变量的名称。
16. objc中向一个nil对象发送消息将会发生什么?
如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。
17.objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?
该方法编译之后就是objc_msgSend()
函数调用.
18. 什么时候会报unrecognized selector的异常?
走完消息传递的流程和消息转发的流程都找不到对应的方法时就会报unrecognized selector的异常
消息传递的流程:
- 根据对象的isa指针找到对象所属的类,在类的cache中找SEL对应的方法,如果找到就去实现,找不到走下一步
- 在类的方法列表中找,找到就去实现,并把方法就如到cache中,找不到走下一步
- 在类的父类方法列表中找,一直到NSObject类为止,如果能找到就去实现,找不到就走消息转发的流程
消息转发的流程:
- objc运行时会调用
+resolveInstanceMethod:
或者+resolveClassMethod:让你动态添加方法实现
-forwardingTargetForSelector:将消息转发给备援接受者
首先它会发送-methodSignatureForSelector消息获得函数的参数和返回值类型。如果methodSignatureForSelector返回nil,Runtime则会发出doesNotRecognizeSelector消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送forwardInvocation消息给目标对象,如果forwardInvocation返回nil,这时也会报doesNotRecognizeSelector异常。
19. 一个objc对象如何进行内存布局?(考虑有父类的情况)
- OC对象的结构图
- isa指针
- 根类的实例变量
- 倒数第二层父类的实例变量
- 。。。。。。
- 父类的实例变量
- 类的实例变量
20.一个objc对象的isa指针指向什么,起什么作用?
指向它的类对象,从而找到类对象上的方法
21.下面的代码输出什么
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end复制代码
Son,Son
22. runtime如何通过selector找到对应的IMP地址?
每一个类对象中都有一个方法列表,方法列表中记载着方法的名称,实现以及参数类型,其实selector本质就是方法名称,通过这个名称在方法列表中就可以找到对应的方法实现。
23. 使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?
无论在MRC下还是ARC下均不需要。
24. objc中的类方法和实例方法有什么本质区别和联系?
类方法
- 类方法是属于类对象的
- 类方法只能通过类对象调用
- 类方法中的self是类对象
- 类方法可以调用其他的类方法
- 类方法中不能访问成员变量
- 类方法中不能直接调用对象方法
实例方法
- 实例方法是属于实例对象的
- 实例方法只能通过实例对象调用
- 实例方法中的self是实例对象
- 实例方法中可以访问成员变量
- 实例方法中直接调用实例方法
- 实例方法中也可以调用类方法(通过类名)