MRC面试题汇总

2016-06-24  本文已影响225人  大橙子1

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];
}
上一篇 下一篇

猜你喜欢

热点阅读