美文网首页
Objective-C 基础

Objective-C 基础

作者: ChenME | 来源:发表于2017-12-07 00:14 被阅读0次

    iOS常用存储方式:

    1. XML属性列表(plist)归档;
    2. Preference(偏好设置);
    3. NSKeyedArchiver 归档(NSCoding);
    4. SQLite3(数据库);
    5. Core Data;

    应用沙盒

    Documents
    Library / Caches
    Library / Preferences
    tmp


    实例变量修饰符

    -- public protect(默认) private
    本类 可以 可以 可以
    子类 可以 可以 不可以
    其他类 可以 不可以 不可以

    package 如果在其他包中访问就是 private 的,如果在当前代码所在的包中访问就是 public 的。


    关键字

    1. @ property (编译器指令):在 xcode4.4 之前,可以使用 @property 来代替 getter/setter 方法的声明;在 xcode4.4 之后,同时可以代替 getter/setter 方法的声明和实现;

    @ property 的修饰符:

    1. readonly :只读(即只生成 getter 方法)
    2. readwrite :可读可写(即生成 getter 方法,也生成 setter 方法,默认
    3. getter=[方法名] :修改 getter 方法的方法名;
    4. setter=[方法名:] :修改 setter 方法的方法名;
    5. retain :自动生成 setter 方法内存管理代码(参见内存管理中的第二点);
    6. assign :不会帮我们生成生成 setter 方法的内存管理代码(默认);
    7. atomic :性能低(单线程,默认
    8. nonatomic :性能高(多线程,在 iOS 开发中基本都使用 nonatomic
    9. strong :在ARC中,用于OC对象,相当于MRC中的 retain
    10. weak :在ARC中,用于OC对象,相当于MRC中的 assign
    11. copy :一般用在字符串后面,可以防止外界修改内部的数据;
    1. @synthesize [参数名 = 属性名] (编译器指令):代替 getter/setter 方法的实现;在 xcode4.4 之后可以使用 @proerty 代替;

    动态数据类型( idinstancetype

    isKindOfClass: // 判断当前对象是否是指定类的对象,或者是指定类子类的对象
    inMemberOfClass: // 判断当前对象是否是指定类的对象
    

    idinstancetype 的区别

    1. id 在编译的时候不能判断对象的真实类型,而 instancetype 可以;(注意:在自定义构造方法时,尽量使用 instancetype
    2. id 可以用来定义变量、可以作为形参、可以作为返回值,而 instancetype 只能用来作为返回值;

    构造方法

    - (instancetype)init{
        if(self = [super init]){
            // 要实现的代码
        }
        return self;
    }
    

    类的启动过程

    只要程序启动就会将所有类的代码加载到内存中,放到代码区

    1. +(void)load 方法会在当前类被加载到内存的时候调用,有且仅会调用一次;

    在继承关系中,会先调用父类的 +(void)load 方法,再调用子类的 +(void)load 方法;

    1. +(void)initialize 方法会在当前类第一次被使用的时候调用(创建类的时候),该方法在整个程序的运行过程中只会被调用一次;

    +(void)load 方法一样,如果存在继承关系,会先调用父类的 +(void)initialize 方法,再调用子类的 +(void)initialize 方法;


    内存管理

    1. ARC:-> Automatic(自动) Reference(引用) Counting(计数),不需要程序员管理内存,编译器会在适当的地方添加 release/retain 等代码;

    OC 中的 ARC 和 Jave 中的垃圾回收机制不太一样,Java 中的垃圾回收时系统干的,而 OC 中的 ARC 是编译器干的;

    1. MRC:-> Manul(手动) Reference(引用) Counting(计数),所有对象的内容都需要我们手动管理,需要程序员自己编写 release/retain 等代码;
    • MRC 中的 setter 方法标准写法:
    -(void) setRoom:(Room *)room{
        if(_room != room){
    
            // 先释放掉原来的 Room 引用计数器( -1 )
            [_room release];
            
            // 对新的 Room 引用计数器 +1,同时进行赋值操作
            _room = [room retain];
        }
    }
    

    ARC

    1. ARC 的判断准则:只要没有强指针指(默认情况下,所有的指针都是强指针)向对象,对象就会被释放。
    2. 强指针、弱指针的表示方法:
    __strong Person *p1 = [[Person alloc] init]; // 强指针
    __weak Person *p2 = [[Person alloc] init]; // 弱指针
    

    在ARC中保存对象不要使用 assign,要使用 weakassign 是专门用于保存基本数据类型的,如果保存对象用 weak
    strong :在ARC中,用于OC对象,相当于MRC中的 retain
    weak :在ARC中,用于OC对象,相当于MRC中的 assign
    assign :在ARC中,用于保存基本数据类型,跟MRC中的 assign 一样;


    Category

    1. 作用:
    • 在不修改原来类的基础上,为这个类扩充一些方法;
    • 一个庞大的类可以分模块开发;
    1. 使用:
    // 声明(在 .h 文件中)
    @interface ClassName (CategoryName)
    // 需要扩充的方法的声明
    @end
    
    // 实现(在 .m 文件中)
    @implementation ClassName (CategoryName)
    // 需要扩充的方法的实现
    @end
    
    1. 注意事项:
    • 分类是用于给原有的类添加方法的,它只能添加方法,不能添加属性(成员变量);
    • 即使在分类中使用了 @property,也只会生成 setter/getter 方法的声明,不会生成实现以及私有的成员变量;
    • 可以再分类中访问原有类中 .h 中的属性;
    • 如果分类中有和原有类同名的方法,会调用分类中的方法(即原有类中的方法会被覆盖掉);
    • 如果多个分类中都有和原有类同名的方法,那么会调用哪个,由编译器决定,编译器会执行最后一个编译的分类中的那个同名方法;

    Block

    1. block 的定义:
    // block 的定义
    // 返回值类型 (^block变量名)(形参列表) = ^返回值类型 (形参列表){};
    
    1. block 的定义、赋值以及调用示例:
    // 1. 定义一个block:
    // int -> 代表 block 将来保存的代码有一个 int 类型的返回值;
    // (^sumBlock) -> 代表 sumBlock 是一个 block 变量,可以用于保存一段 block 代码;
    // (int, int) -> 代表 block 将来保存的代码需要两个 int 类型的参数;
    int (^sumBlock) (int, int);
    
    // 2. 给 block 赋值:
    // int -> 表示返回值类型为 int,可省略
    // ^ -> 代表是一个 block 代码块;
    // (int num1, int num2) -> 代表需要两个 int 类型的形参,形参名分别为 num1 和 num2;
    sumBlock = ^int (int num1, int num2){
        // 想要封装的代码段 ... ...
        return num1 + num2;
    };
    
    // 3. 调用 block:
    int sum = sumBlock(1, 2);
    NSLog(@"sum = %i", sum);
    
    1. Block 与 typedef 的结合使用:
    typedef int (^calculate)(int, int); // 给 block 起一个别名叫 calculte
    void useBlock1(){
        
        calculate sumBlock = ^(int value1, int value2){
            return value1 + value2;
        };
        NSLog(@"sum = %i", sumBlock(20, 10));
        
        calculate minusBlock = ^(int value1, int value2){
            return value1 - value2;
        };
        NSLog(@"minus = %i", minusBlock(20, 10));
    }
    
    1. 注意事项:
    • block 中可以访问外面的变量;
    void announcementsOfBlock(){
        // 1. block 中可以访问外面的变量;
        int a = 10;
        void (^blockTest)() = ^void (){
            NSLog(@"a = %i",a); // 输出结果 a = 10
        };
        blockTest();
    }
    
    • block 中可以定义和外面同名的变量,并且如果如此定义了,在 block 中访问的是 block 的变量;
    void announcementsOfBlock(){    
        // 2. block 中可以定义和外面同名的变量,并且如果如此定义了,在 block 中访问的是 block 的变量
        int a = 10;
        void (^blockTest)() = ^void{
            int  a = 20;
            NSLog(@"a = %i",a); // 输出结果 a = 20
        };
        blockTest();
    }
    
    • 默认情况下,不可以在 block 中修改外面的值;<因为 block 中的变量和外面的变量并不是同一个,如果 block 中访问到了外面的变量,block 会将外面的变量拷贝一份到堆内存中。>
    void announcementsOfBlock(){
        // 3. 默认情况下,不可以在 block 中修改外面的值;
        int a = 10;
        void (^blockTest)() = ^(){
            // a = 20; // 此处会编译失败
        };
        blockTest();
    }
    
    • 如果想在 block 中修改外面的变量,需要在声明变量时加上 __block
      • 在不加 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的值作为参数传入到 block 块中;
      • 在加上 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的地址作为参数传入到 block 块中;
    void announcementsOfBlock(){
        // 4. 如果想在 block 中修改外面的变量,需要在声明变量时加上 __block
        // 在不加 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的值作为参数传入到 block 块中
        // 在加上 __block 时,在 block 块中访问外面的变量 a 时,是把 a 的地址作为参数传入到 block 块中
        __block int a = 10;
        void (^blockTest)() = ^{
             a = 20;
        };
        blockTest();
        NSLog(@"a = %i",a); // 输出结果 a = 20
    }
    
    • 默认情况下,block 存储在栈中,如果对 block 进行一个 copy 操作,block 会转移到堆中。
      • 如果 block 在栈中,并且访问了外面的对象,那么不会对对象进行 retain 操作;
      • 但如果 block 在堆中,并且访问了外面的对象,那么会对外面的对象进行一次 retain 操作的;
      • 总结:如果在 block 中访问了外面的对象,一定要给对象加上 __block,这样哪怕 block 在堆中,也不会对外面的对象进行 retain;

    协议(protocol)

    1. 语法格式:
    // 例如下面一个运动的协议
    @protocol SportProtocol <NSObject>
    // 方法的声明列表
    - (void)playFootball;
    - (void)playBasketball;
    - (void)playBaseball;
    @end
    
    1. 特点:
    • 协议只有声明,没有实现(与分类的区别,分类有实现);
    • 协议只能声明方法,不能声明属性(与分类相似);
    • 父类遵守了某个协议,那么子类也会自动遵守这个协议;
    • OC 中一个类可以遵守1个或多个协议;
    • OC 中的协议又可以遵守其他协议,只要一个协议遵守了其他协议,那么这个协议中就会自动包含其他协议的声明;
    1. 协议中的关键字:
    • @required :这个方法必须实现,若不实现,编译器会发出警告(默认);
    • @optional :这个方法不一定要实现;

    注意: @required@optional 仅仅是用于程序员之间的交流,并不能严格的控制某一个遵守该协议的类必须要实现该方法,因为即使不实现,也不会报错,只会抱一个警告。


    copy相关

    1. 如果是浅拷贝,那么系统就会对原来的对象进行 retain

    持续更新中... ...


    相关文章

      网友评论

          本文标题:Objective-C 基础

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