美文网首页
iOS基础知识

iOS基础知识

作者: i_can_fan | 来源:发表于2019-01-22 11:48 被阅读0次

    1.对属性修饰符的理解

    MRC下

    assign

    主要用于修饰基本数据类型,setter方法也只是简单的赋值,例如NSInter,CGFloat 如果用来修饰对象,并不持有对象,那么对象的引用计数不变,如果这个时候对象被释放了,他就可能成为野指针,不手动置为nil,在堆上很容易造成崩溃,而如果修饰的不是对象,那么栈上的内存系统会自动处理,不会造成野指针

    retain

    修饰对象,不能修饰基本数据类型 ,引用计数+1,适用于NSObject及子类

    ARC下

    Strong

    对应的setter方法是先release,然后再把参数retain,最后成员变量赋值,类似于retain

    表示指向并拥有对象,其修饰的对象引用计数会+1,该对象只要引用计数不为0则不会被销毁,当然强行置为nil可以销毁他

    Copy

    对应的setter方法是先release,然后copy参数内容,创建一个新的内存地址,因此修改之前的地址不会修改到副本,减少对上下文的依赖,copy一般用于修饰具有可变应用类型的不可变对象身上,例如NSArray,NSString,NSDictionary,,为什么呢?看下例子

        @property(nonatomic,strong) NSString *testStrongName;
        @property(nonatomic,copy) NSString * testCopyName;
     
        self.testStrongName = @"test1";
        self.testCopyName = @"test1";
        NSLog(@"strong====%@    p==== %p",self.testStrongName,self.testStrongName);
        NSLog(@"copy======%@    p==== %p",self.testCopyName,self.testCopyName);
    
        NSMutableString *mStr = [[NSMutableString alloc]initWithString:@"TestM2"];
        self.testStrongName = mStr;
        self.testCopyName = mStr;
        NSLog(@"mStr==== %p",mStr);
        
        [mStr appendString:@"111"];//mstr不改地址
        
        NSLog(@"mStr==== %p",mStr);
    
        mStr = [NSMutableString stringWithFormat:@"test2"];//mstr改地址
        NSLog(@"mStr==== %p",mStr);
    
        [mStr appendString:@"111"];
    
        NSLog(@"strong====%@    p==== %p",self.testStrongName,self.testStrongName);
        NSLog(@"copy======%@    p==== %p",self.testCopyName,self.testCopyName);
    
        //打印结果为
       2019-01-22 11:42:33.286277+0800 OC-test1[18667:237712] [default] Unable to load   
       Info.plist exceptions (eGPUOverrides)
       2019-01-22 11:42:33.338443+0800 OC-test1[18667:237660] strong====test1    p==== 
       0x100002058
       2019-01-22 11:42:33.338476+0800 OC-test1[18667:237660] copy======test1    
       p==== 0x100002058
       2019-01-22 11:42:33.338495+0800 OC-test1[18667:237660] mStr==== 
       0x600000c053e0
       2019-01-22 11:42:33.338511+0800 OC-test1[18667:237660] mStr==== 
        0x600000c053e0
       2019-01-22 11:42:33.338535+0800 OC-test1[18667:237660] mStr==== 
       0x600000c05410
       2019-01-22 11:42:33.338569+0800 OC-test1[18667:237660] strong====TestM2111    
       p==== 0x600000c053e0
       2019-01-22 11:42:33.338584+0800 OC-test1[18667:237660] copy======TestM2    
       p==== 0x5f8f2f5af9a6eb4d
    
    

    可以看到,本身是不可变类型NSString,但是它会有可变类型的属性在,如果你用Strong修饰他,当该指针指向了NSMutableString类型的数据,Strong只是把源数据的多了一个新的指针指向而已,当源数据改变,那么原来设置的name不可变类型,就可以变了。这就是上面遇到修改之前的数据改变了现有的数据,上下文依赖了,因此copy来减少上下文依赖,如果本身是不可变类型NSstring,那么Strong也一样,如果变成可变类型了,那么减少上下文依赖,copy就会对可变类型执行深copy,从而让数据源更干净

    strong和copy都会使引用计数加1,但strong使两个指针指向同一个内存地址,copy则会在内存里拷贝一份对象,两个指针指向不同的内存地址

    针对copy这个属性,以string类型为例,copy就是普通的指针copy(浅copy),而mutableCopy就是内容copy(深copy),如果是mutableString类型的话,那么copy就全是内容copy了 如果是容器类型,例如NSArray和NSDictionary,copy属性操作的指针针对容器本身,而容器内部的都还是同一个指针引用,并不会根据容器的copy或者strong而变化,指针根据自己的属性修饰符有关

    • weak 不会保留传入的属性,不会使对象的引用计数+1,类似assign,但是当对象被释放时,weak自动置nil,这就是weak区别assgin最大的区别 小知识:当属性是readwrite的时候,如果重写了getter的方法,那么setter方法是系统提供的,那么系统顺便帮我们实现了成员变量,但是如果你重写了setter和getter方法,那么这个时候你把系统的两个方法都实现了,那么系统就需要你自己去实现成员变凉了,不然是无法获取到的,你可以再implementation或者extension里面进行实现,或者在h文件实现,前两者是@private的,后者是共有的

    weak 和 assign的理解

    1.assign适用于基本数据类型,weak是适用于NSObject对象,并且是一个弱引用。 2.assign其实也可以用来修饰对象。那么我们为什么不用它修饰对象呢?因为被assign修饰的对象(一般编译的时候会产生警告:Assigning retained object to unsafe property; object will be released after assignment)在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,造成野指针。对象一般分配在堆上的某块内存,如果在后续的内存分配中,刚好分到了这块地址,程序就会崩溃掉。 3.那为什么可以用assign修饰基本数据类型?因为基础数据类型一般分配在栈上,栈的内存会由系统自己自动处理,不会造成野指针。 4.weak修饰的对象在释放之后,指针地址会被置为nil。所以现在一般弱引用就是用weak。weak使用场景: 5.在ARC下,在有可能出现循环引用的时候,往往要通过让其中一端使用weak来解决,比如: delegate代理属性,通常就会声明为weak。 自身已经对它进行一次强引用,没有必要再强引用一次时也会使用weak。比如:自定义 IBOutlet控件属性一般也使用weak,当然也可以使用strong。

    __block与__weak的区别

    __block是用来修饰一个变量,这个变量就可以在block中被修改
    __block:使用 __block修饰的变量在block代码块中会被retain(ARC下会retain,MRC下不会retain)
    __weak:使用__weak修饰的变量不会在block代码块中被retain
    同时,在ARC下,要避免block出现循环引用 __weak typedof(self)weakSelf = self;
    这两个都是和block相关,block就是OC对闭包的实现,闭包就是匿名函数,或者理解为指向函数的指针
    block变量定义时为什么用copy?block是放在哪里的?
    block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,可能被随时回收,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。通过copy可以把block拷贝(copy)到堆,保证block的声明域外使用。

    特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。

    [array addObject:[[^{
        NSLog(@"hello!");
    } copy] autorelease]];
    

    nil,Nil,NULL和NSNull理解

    nil

    nil 是 ObjC 对象的字面空值,对应 id 类型的对象,或者使用 @interface 声明的 ObjC 对象。
    例如:

    NSString *someString = nil;
    NSURL *someURL = nil;
    id someObject = nil;
    if (anotherObject == nil) // do something
    

    定义:

    #ifndef nil
    # if __has_feature(cxx_nullptr)
    #   define nil nullptr
    # else
    #   define nil __DARWIN_NULL
    # endif
    #endif
     
    // __DARWIN_NULL in _types.h
     
    #define __DARWIN_NULL ((void *)0)
    
    Nil

    Nil 是 ObjC 类类型的书面空值,对应 Class 类型对象。
    例如:

    Class someClass = Nil;
    Class anotherClass = [NSString class];
    

    定义声明和 nil 是差不多的,值相同:

    #ifndef Nil
    # if __has_feature(cxx_nullptr)
    #   define Nil nullptr
    # else
    #   define Nil __DARWIN_NULL
    # endif
    #endif
    
    NULL

    NULL 是任意的 C 指针空值。
    例如:

    int *pointerToInt = NULL;
    char *pointerToChar = NULL;
    struct TreeNode *rootNode = NULL;
    

    定义:

    // in stddef.h
     
    #define NULL ((void*)0)
    
    NSNull

    NSNull 是一个代表空值的类,是一个 ObjC 对象。实际上它只有一个单例方法:+[NSNull null],一般用于表示集合中值为空的对象。
    例子说明:

    // 因为 nil 被用来用为集合结束的标志,所以 nil 不能存储在 Foundation 集合里。
    NSArray *array = [NSArray arrayWithObjects:@"one", @"two", nil];
     
    // 错误的使用
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:nil forKey:@"someKey"];
     
    // 正确的使用
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:[NSNull null] forKey:@"someKey"];
    

    定义:

    NSNull.h
    #import <Foundation/NSObject.h>
    @interface NSNull : NSObject <NSCopying, NSSecureCoding>
    + (NSNull *)null;
    @end
    
    NIL 或 NSNil

    ObjC 不存在这两个符号!

    转载参考
    iOS基础面试知识点总结 - Deft_MKJing的博客 - CSDN博客
    nil,Nil,NULL和NSNull理解(ios)

    相关文章

      网友评论

          本文标题:iOS基础知识

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