No.1
//1.计数器的基本操作
// 假设有狗这个类
// 请找出不合理或者错误的地方
@class Dog;
@interface Person : NSObject
@property (nonatomic,retain) Dog *dog;
@end
@implementation Person//
@end
int main()
{
Person *p = [[Person alloc] init];
[p release];
// [p retain];
Person *p2 = [[Person alloc] init];
//[p2 dealloc];
[p2 release];
Person *p3 = [[Person alloc] init];
Dog *d = [[Dog alloc] init];
p3.dog = d;
//[d release];
[p3 release];
return0;
}
No.2 @property使用
// 假设有Dog类、Car类
// 请找出不合理或者错误的地方
@interface Person : NSObject
@property (nonatomic, assign) Car *car;//要使用retain不能使用assign
@property (nonatomic,atomic, retain) int age;//nonatomic和atomic是一组相对应的函数,只可用一个,int age是个变量不是对象不存在retain要用assign
@property (nonatomic,readwrite, readonly) int height;//readwrite和readonly是一组,只读,和可读可写的内容是相互冲突的只可以选择一个
@property (nonatomic,retain, setter=setMyDog) Dog *dog;//一般不要改setter方法,并且set方法名还有:冒号
@end
@implementation Person
- (void)dealloc
{
[_car release];
//[_age release];
//[_height release];
[_dog release];
[super dealloc];
}
@end
No.3 autorelease使用
// 假设有个Person类
// 请找出不合理或者错误的地方
int main()
{
@autoreleasepool
{
Person *p = [[[Person alloc] init] release];
Person *p1 = [[[Person alloc] init] autorelease];
[p1 release];//自动释放池中不用写release
//[p release];
Person *p2 = [[[[Person alloc] init] autorelease] autorelease];// 多一个autorelease
}
return0;
}
No.4 autorelease使用
// 假设有个Person类,有个@property (nonatomic, assign) int age;
// 请找出不合理或者错误的地方
int main()
{
Person *p = nil;
@autoreleasepool
{
p = [[Person alloc] init];
@autoreleasepool
{
[p autorelease];
}
[p setAge:10];// 野指针
}
return0;
}
野指针指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。
No.5 请解释以下keywords的区别: assign vs weak, __block vs __weak
assign 适用于基本数据类型, weak适用于NSObject对象,并且是个弱引用。
block是用来修饰一个变量的,这个变量可以在block中被修改(ARC下)。使用block修饰的变量,在block代码块中会被retain(ARC下,MRC下不会)。
使用weak修饰的变量不会在block代码块中被retain。在ARC下,为了避免循环引用,使用weak typeof(self)weakSelf = self;
No.6 __block在arc和非arc下含义一样吗?
是不一样的。
在ARC下,__blcok修饰的变量,在block代码块中会被retain。在MRC下,__blcok修饰的变量,在block代码块中不会被retain。
与之相反的是__weak,__unsafe_unretained. (__weak修饰的变量在release后,此pointer会自动设置为nil)
为了解决循环引用
__blcok MyClass temp = …; //MRC下使用
__weak MyClass temp = …; //ARC下使用,iOS5.0以上的版本
__unsafe_unretained MyClass temp = …; //ARC下,且IOS4.x以后版本
No.6 什么是arc?(arc是为了解决什么问题诞生的?)
首先解释ARC: automatic reference counting自动引用计数。 ARC几个要点: 在对象被创建时 retain count +1,在对象被release时 retain count -1.当retain count 为0 时,销毁对象。 程序中加入autoreleasepool的对象会由系统自动加上autorelease方法,如果该对象引用计数为0,则销毁。 那么ARC是为了解决什么问题诞生的呢?这个得追溯到MRC手动内存管理时代说起。 MRC下内存管理的缺点: 1.当我们要释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放) 2.释放指针指向的堆空间,首先要确定哪些指针指向同一个堆,这些指针只能释放一次。(MRC下即谁创建,谁释放,避免重复释放) 3.模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁去释放。 4.多线程操作时,不确定哪个线程最后使用完毕
No.7 使用nonatomic一定是线程安全的吗?()
atomic:线程安全,需要消耗大量系统资源来为属性加锁
nonatomic:非线程安全,适合内存较小的移动设备
No.8 描述一个你遇到过的retain cycle例子
block中的循环引用:一个viewController
@property (nonatomic,strong)HttpRequestHandler *handler;
@property (nonatomic,strong)NSData *data;
_handler = [httpRequestHandler sharedManager];
[_handler downloadData:^(id responseData){ _data = responseData; }];
//self 拥有_handler, _handler 拥有block, block拥有self(因为使用了self的_data属性,block会copy 一份self)
//解决方法:
__weak typedof(self)weakSelf = self
[_handler downloadData:^(id responseData){ weakSelf.data = responseData; }];
//如果是倒霉催的项目还需要支持iOS4.3,就用__unsafe_unretained替代__weak。
//如果是non-ARC环境下就将__weak替换为__block即可。
non-ARC情况下,__block变量的含义是在Block中引入一个新的结构体成员变量指向这个__block变量,那么__block typeof(self) weakSelf = self。
就表示Block别再对self对象retain啦,这就打破了循环引用。
图解
block循环引用.png
No.9 autorelease
// 假设有个Person类,请问p1、p2、p3、p4指向的对象分别在第几行代码后会销毁
int main()
{
Person *p1 = nil;
@autoreleasepool
{
p1 = [[Person alloc] init];
}
@autoreleasepool
{
[p1 autorelease];//p1
Person *p2 = [[[Person alloc] init] autorelease];//p2
Person *p3 = [[Person alloc] init];
@autoreleasepool
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[p3 autorelease];//p3
Person *p4 = [[Person alloc] init];
[pool release];
[p4 autorelease];//p4
} //p4 p3 释放
} // p2 p1 释放
return 0;
}
No.10 block一般用那个关键字修饰,为什么?
block一般使用copy关键之进行修饰,block使用copy是从MRC遗留下来的“传统”,在MRC中,方法内容的block是在栈区的,使用copy可以把它放到堆区。但在ARC中写不写都行:编译器自动对block进行了copy操作。
No.11 用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
答:用@property声明 NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
copy此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。
No.12 runloop、autorelease pool以及线程之间的关系。、
每个线程(包含主线程)都有一个Runloop。对于每一个Runloop,系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个像callstack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。
No.13 分别写一个setter方法用于完成@property (nonatomic,retain)NSString *name和@property (nonatomic,copy) NSString *name
retain属性的setter方法是保留新值并释放旧值,然后更新实例变量,令其指向新值。顺序很重要。假如还未保留新值就先把旧值释放了,而且两个值又指向同一个对象,先执行的release操作就可能导致系统将此对象永久回收。
-(void)setName:(NSString *)name
{
[name retain];
[_name release];
_name = name;
}
-(void)setName:(NSString *)name
{
[_name release];
_name = [name copy];
}
网友评论