美文网首页
iOS 每天一道面试题

iOS 每天一道面试题

作者: 木木等你 | 来源:发表于2017-03-24 17:41 被阅读53次

    同为菜逼,共同努力。

    1.nil Nil NULL NSNull 区别。

    nil:指向oc中对象的空指针,针对对象。

    Nil:指向oc中类的空指针,针对类。

    NULL:指向其他类型的空指针,如一个c类型的内存指针,基本数据类型为空,基本类型。

    NSNull:在集合对象中,表示空值的对象。

    参考博客这是我发现写的比较详细的博客.

    2.你是否接触过oc中的反射机制?简单聊一下概念和使用.

        //    • class反射
        //    • 通过类名的字符串形式实例化对象
        Class class1 = NSClassFromString(@"UILabel");
        id label = [[class1 alloc ]init];
        NSLog(@"label = %@",label);
        //    • 将类名变为字符串
        Class class2 =[UILabel class];
        NSString *className = NSStringFromClass(class2);
        NSLog(@"className = %@",className);
    
        Student *stu = [[Student alloc] init];
        //    • SEL的反射
        //    • 通过方法的字符串形式实例化方法
        SEL selector = NSSelectorFromString(@"setName:");
        [stu performSelector:selector withObject:@"GanMaoShen"]; //注意如果有两个参数,使用两个withObject:参数;
        NSLog(@"stu.name =%@",stu.name);
        //    • 将方法变成字符串
        NSString *select =  NSStringFromSelector(@selector(testVoidFuncWithTestParam:));
        NSString *select2 =  NSStringFromSelector(_cmd);
        NSLog(@"select =%@ select2 = %@",select,select2);
    
    2017-03-27 20:19:07.658 test[10559:3059755] label = <UILabel: 0x7fdcae00fed0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000002834d0>>
    2017-03-27 20:19:07.659 test[10559:3059755] className = UILabel
    2017-03-27 20:19:07.659 test[10559:3059755] stu.name =GanMaoShen
    2017-03-27 20:19:07.659 test[10559:3059755] select =testVoidFuncWithTestParam: select2 = viewDidLoad
    

    3.Block的传值,传址,内存管理,循环引用(retain cycle)。(狠补了一下block的知识,发现block中很多知识点,所以还是要弄透)

    两篇很好的block基础博客
    block的用法,定义.
    block两个界面的传值.

    void test1()
    {
      int a = 10;
    }
    void test2()
    {
        __block int a = 10;
    }
    void test3()
    {
        static int a = 10;
    }
    int a = 10;
    void test4()
    {
    }
    总结:block中只有普通局部变量(test1)是传值,其他情况(test2,test3,test4)都是传址。
    
    #block的内存管理
    ARC下:
    - block可以使用copy和strong,并且是一个对象。
    
    #Block如果没有引用外部变量
    保存在全局区(MRC/ARC一样)
    #Block如果引用外部变量
    ARC保存在 堆区; MRC保存在 栈区必须用copy修饰block;
    

    推荐博客深入浅出-iOS Block原理和内存中位置

    block循环引用
    1.如果block代码块的内部,使用了外面的强引用对象,block代码块的内部会自动产生一个强引用,引用着该对象,不会销毁,造成循环引用.
    解决:下面代码在block外部实现.
    __weak typeof(self) weakSelf = self; 
    #define WeakSelf(type)  __weak typeof(type) weak##type = type;
    2.但是如果在block内部使用延时操作的还使用弱指针的话会取不到该弱指针,需要在block内部再将弱指针强引用一下.
    __strong typeof(self) strongSelf = weakSelf;
    #define StrongSelf(type)  __strong typeof(type) strong##type = weak##type;
    

    关于循环引用很好的博客Swift与OC真正去理解Block解决循环引用的技巧

    4.如何在@category和@protocol中添加@property

    首先你要知道category和protocol和作用和区别,同时回顾这道题的同时,同时回顾extension 和category。
    extension看起来很像一个匿名的category,但是extension和有名字的category几乎完全是两个东西。 extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension。
    更深入一点的话我推荐这个帖子。iOS 类别不能添加属性原理?

    @dynamic 和 @synthesize的区别:
    在@implementation 中通过@dynamic xxx 告诉编译器、xxx属性的setter、getter方法由开发者自己来生成
    @ synthesize xxx = _xxx; 告诉编译器、xxx属性的setter、getter方法由编译器来生成、同时用_xxx 来合成 成员变量

    好,步入正题。

    4.1@protocol中添加property

    在protocol中添加property时,其实就是声明了 getter 和 setter 方法,在实现这个protocol协议的类中,我们要自己手动添加实例变量,并且需要实现setter/getter方法,实现setter/getter方法有两种方式,一种是自动生成(@synthesize) ,另一种是手动生成(@dynamic)此时又有了拓展问题(@synthesize和@dynamic的作用 见 题5)

    @protocol PersonDelegate <NSObject>
    @property (nonatomic, copy) NSString *name;
    @end
    //personn类
    @interface Person : NSObject
    @end
    
    #import "Person.h"
    @interface Student : NSObject <PersonDelegate>
    - (void)testLog;
    @end
    
    #import "Student.h"
    
    @implementation Student
    //自动实现setter和getter方法
    @synthesize name;
    
    - (void)testLog {
        NSLog(@"self.name=%@",self.name);
    }
    
    @end
    

    手动实现setter和getter

    #import "Person.h"
    @interface Student2 : NSObject <PersonDelegate>
    {
        //声明一个实例变量
        NSString *_name;
    }
    - (void)testLog;
    @end
    
    #import "Student2.h"
    
    @implementation Student2
    @dynamic name;
    - (void)testLog {
        NSLog(@"self.name=%@",self.name);
    }
    - (void)setName:(NSString *)name
    {
        _name = name;
    }
    - (NSString *)name
    {
        return _name;
    }
    @end
    
        Student *stu1 = [Student new];
        stu1.name = @"testName";
        [stu1 testLog];
        Student2 *stu2 = [Student2 new];
        stu2.name = @"testName";
        [stu2 testLog];
    

    关于category实现property主要是利用runtime的关联方法(mjrefresh中也有用到)。

    objc_setAssociatedObject   objc_getAssociatedObject
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *tmpName;
    - (void)testLog;
    @end
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    - (void)setTmpName:(NSString *)tmpName
    {
        objc_setAssociatedObject(self, @selector(tmpName), tmpName, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    - (NSString *)tmpName
    {
        return objc_getAssociatedObject(self, @selector(tmpName));
    }
    - (void)testLog {
        NSLog(@"self.name=%@",self.tmpName);
    }
    @end
    
        Person *p1 = [Person new];
        p1.tmpName = @"tmpName";
        [p1 testLog];
    

    当然还有一种利用临时变量的方法完成添加属性的方法。参考博客
    iOS Category 和 Protocol 中的 Property 你们真的会了么?

    相关文章

      网友评论

          本文标题:iOS 每天一道面试题

          本文链接:https://www.haomeiwen.com/subject/samfottx.html