简述OC基础语法的一些坑洞

作者: iOS佥 | 来源:发表于2018-03-21 21:35 被阅读5次

    1. 标识符的规则

    1. 字母、数字、下划线、美元符$,但是不能以数字开头;
    2. 区分大小写
    3. 不能是关键字

    2. #import 和 #include 的区别

    • include 的作用就是将指定的源代码插入到当前源代码的位置,如果导致了重复导入,不会给出提示

    • Objective-C 提供的 #import 更加智能,可以帮助程序员判断,避免重复导入的问题

    3. OC 的块

    OC 的块类似 Swift 的闭包,像一个匿名函数B,在定义的时候无须指定名字,通常的用法是作为函数A的参数,在调用 A 的时候实时定义 B,使得代码更加灵活:

    #import <Foundation/Foundation.h>
    typedef void (^FKProcessBlock)(int);  // 定义一个块类型
    // 使用FKProcessBlock定义最后一个参数类型为块
    void processArray(int array[] 
        , unsigned int len, FKProcessBlock process)
    {
        for(int i = 0 ; i < len; i ++)
        {
            process(array[i]);  // 将数组元素作为参数调用块
        }
    }
    int main(int argc , char * argv[])
    {
        @autoreleasepool{
            int arr[] = {2, 4, 6};  // 定义一个数组
            // 传入块作为参数调用processArray()函数
            processArray(arr , 3 , ^(int num)
            {
                NSLog(@"元素平方为:%d" , num * num);
            });//注意这里大括号中的是块的定义
        }
    }
    
    

    4. id类型

    id类型是Objective-C提供的一个特有类型,这个类型可以代表所有对象的类型,也就是说,任意类的对象都可以赋值给id类型的变量
    当通过id类型的变量来调用方法时,Objective-C会执行动态绑定,在程序运行时自动判断对象所属的类,确定需要动态调用的方法

    5. 单例模式 Singleton

    某些时候,我们要使用的类只用到一个实例,例如一个窗口管理器,这时候就可以用到单例类,保证这个类始终只能创建一个对象。常用写法:

    // 接口部分
    #import <Foundation/Foundation.h>  
      
    @interface Singleton : NSObject  
      
    +(instancetype) shareInstance ;  
      
    @end  
      
      
    // 实现部分
    #import "Singleton.h"  
      
    @implementation Singleton  
    /*
     用 static 全局变量实现,每次程序获取该实例前都要先判断该 static 全局变量是否为 nil:
     如果为 nil 就初始化实例;
     如果不为 nil,程序直接返回该全局变量指向的实例。
    */
    static Singleton* _instance = nil;  
      
    +(instancetype) shareInstance  
    {  
        static dispatch_once_t onceToken ;  
        dispatch_once(&onceToken, ^{  
            _instance = [[self alloc] init] ;  
        }) ;  
          
        return _instance ;  
    }  
      
    @end 
    
    // 测试程序
    #import "Singleton.h"
    
    int main(int argc , char * argv[]) {
        @autoreleasepool{
        // 判断两次获取的实例是否相等,程序将返回1(代表真)
        NSLog(@"%d", [Singleton instance] == [[Singleton instance];
        }
    }
    

    测试程序如下

    6. 访问控制符

    OC中提供了4个访问控制符:@private @package @protected @public。

    • @private(当前类访问权限):成员只能在当前类内部可以访问,在类实现部分定义的成员变量相当于默认使用了这种访问权限。
    • @package(同映像访问权限):成员可以在当前类或和当前类实现的同一映像中使用。同一映像就是编译后生成的同一框架或同一个执行文件。
    • @protected(子类访问权限):成员可以在当前类和当前类的子类中访问。在类接口部分定义的成员变量默认是这种访问权限。
    • @public(公共访问权限):成员可以在任意地方访问。
    @private @packge @protected @public
    同一个类中
    同一个映像中
    子类中
    全局范围

    7. 合成存取 @property

    系统自动合成 setter 和 getter 方法:

    1. 在接口部分 @interface@end 之间使用 @property指令 定义属性(无须放在花括号中);
    2. (可选)在类实现部分使用 @synthesize指令 改变对应的成员变量名。

    8. @property 指示符

    ①. atomic/nonatomic 线程管理

    指定合成存取方法是否为原子操作,可以理解为是否线程安全,但在iOS上即时使用atomic也不一定是线程安全的。
    可以发现几乎所有代码的属性设置都会使用nonatomic,这样能够提高访问性能,在iOS中使用锁机制的开销较大,会损耗性能。


    ②. readwrite/readonly 读写端丽

    • readwrite是编译器的默认选项,表示自动生成getter和setter,如果需要getter和setter不写即可。
    • readonly表示只合成getter而不合成setter。

    ③. assign,retain,strong,weak,copy,unsafe_unretained 内存管理

    • assign: 简单赋值,不更改索引计数(Reference Counting)。适用于基础类型(简单类型,原子类型):NSInteger,CGPoint,CGFloat,C数据类型(int,float,double,char等)。
    • retain:释当把某个对象赋值给该属性时,该属性原来所引用的对象的引用计数减1,被赋值对象的引用计数加1。在未启用ARC机制的的情况下,retain可以保证一个对象的引用计数大于1时,该对象不会被回收。启用ARC后一般较少使用retain。
    • strong 指示符该属性对被赋值对象持有强引用,强引用的意思是:只要该强引用指向被赋值的对象,那么该对象就不会自动回收。
    • weak 指示符该属性对被赋值对象持有弱引用,弱引用的意思是:即使该弱引用指向被赋值的对象,该对象也可能被回收。
    • copy:如果使用copy指示符,当调用setter方法对成员变量赋值时,会将被赋值的对象复制的一个副本,再将该副本给成员变量,相应的原先的被赋值的对象的引用计数加1。当成员变量的类型是可变类型,或其子类是可变类型,被赋值的对象在赋值后有可能再被修改,如果不需要这种修改,则可以考虑copy指示符。
    • unsafe_unretained:与weak不同,被unsafe_unretained指针所引用的对象被回收后,unsafe_unretained指针不会被赋为nil,可能会导致程序出错。

    9.类别,拓展

    当你已经封装好了一个类(也可能是系统类、第三方库),不想在改动这个类了,可是随着程序功能的增加需要在类中增加一个方法,这时我们不必修改主类,只需要给你原来的类增加一个分类。
    将一个大型的类拆分成不同的分类,在不同分类中实现类别声明的方法,这样可以将一个类的实现写到多个.m文件中,方便管理和协同开发。

    @interface 主类类名(分类类名)
    //不可以定义成员属性
    @end
    
    @implementation 主类类名(分类类名)
    
    @end
    

    扩展是分类的一种特殊形式,通常定义在主类.m文件中,扩展中声明的方法直接在主类.m文件中实现。
    分类是不可以声明实例变量,通常是公开的,文件名是:主类名+分类名.h
    扩展是可以声明实例变量,是私有的,文件名为:主类名_扩展标识.h,在主类的.m文件中#import该头文件

    10.协议,委托

    协议文件的创建

    1. 新建文件
    2. 选择iOS平台Source中的Object-C Fie
    3. 选择File Type为protocol,则可建立协议文件

    协议文件的特征

    1. 协议文件为单一的.h文件
    2. 命名规则一般为”类名Delegate.h”

    使用格式

    .h文件中的格式为

    #import <Foundation/Foundation.h>
    
    @protocol 类名Delegate <NSObject>
    
    // 在此声明协议方法
    // @requires修饰的声明方法,代理方必须实现
    // @optional修饰的声明方法,代理方可以不实现
    
    @end
    

    使用方法

    委托方将该协议文件导入自己的.h文件中,并添加一个遵守该协议的代理属性

    注:就像一般把扩展写在.m文件中,而不单独建立一个扩展文件一样;一般开发中,不单独建立一个协议文件,而是将协议制定在委托方的.h文件中。

    相关文章

      网友评论

        本文标题:简述OC基础语法的一些坑洞

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