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

1. 标识符的规则

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

2. #import 和 #include 的区别

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

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

3. OC 的块

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

#import 
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   
  
@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 

@protocol 类名Delegate 

// 在此声明协议方法
// @requires修饰的声明方法,代理方必须实现
// @optional修饰的声明方法,代理方可以不实现

@end

使用方法

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

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

你可能感兴趣的:(简述OC基础语法的一些坑洞)