YOU'VE MADE A BRAVE DECISION, WELCOME.

每一个不曾起舞的日子都是对生命的辜负。

Objective-C基础累计

基础累计

  • 经典命名法则:

    • 匈牙利命名法:
      • 该命名法则就是在每个变量名前面加上若干表示数据类型的字符。
      • 基本原则就是:变量名 = 属性 + 类型 + 对象描述
      • 比如以i开头的属性表示int类型
    • 驼峰命名法
      • 混合使用大小写字母开构成变量和函数名字,首字母小写
    • 帕斯卡命名法
      • 首字母大写,其它同驼峰
  • 命名规则

    • 变量名首字母必须为字母、下划线、@、或者$开始
    • 变量名只能是字母,数字,下划线、@组合,不能有空格
    • 不能用编程语言的保留字
  • 运算符

    • 一元负号运算符具有更高的优先级,但一元正号运算符和算术运算符的优先级相同

      • 例如:c = -a * b,将执行-a再乘以b。
    • 模运算符的优先级与乘法和除法的优先级相等

      • a + b % c,即a + (b % c)
    • 加法运算符比赋值运算符优先级高,除了逗号运算符其他都比赋值运算符优先级高

      • a /= b + c,即a = a / (b + c)
  • @synthesize 和 @property

    • @property
      • 如果在@interface中声明的 x 变量,编译器将会自动生成getter和setter的方法,编译器也会将生成的实例变量加上下划线( _ )变成 _x。
    • @synthesize
      • 如果在@interface中声明的 x 变量,编译器将会自动生成getter和setter的方法,如果在实现代码部分声明 @synthesize x;或者@synthesize x = _x;编译器生成的实例变量就是你在@interface中声明的实例变量。
      • 如果在@interface中声明的 x 变量,但你没有在@interface声明其它实例变量如a,而直接在代码部分声明synthesize x = a;那么编译器会给你生成一个a的实例变量,而且只会只能访问实例变量a不能访问_a也不能访问x_x
  • 变量初始值

    • 局部变量:初始值为nil,所以需要使用前初始化
      • 调用方法或者执行语句时纯在,存储在栈中。
    • 实例变量:初始值为0
      • 随着对象的创建而存在,随着对象的消失而消失,存储在堆中。
      • 对象持有数据
    • 静态变量(static):初始值为0
      • 可以通过对象或者类调用,存储在方法区的静态区
      • 随着类的创建而存在,类的消失而消失
      • 共享数据
  • self = [super init]

    • 首先要调用父类的init方法,目的是将所有要调用的父类方法初始化
    • 其次是赋给self,因为为了防止父类初始化时release调self指向的空间而alloc一块,但是又可能alloc失败,这样就无法执行if语句。
  • define

    • 宏定义define是一个变量,没有类型信息,在内存中会有多个拷贝。
    • 也可以定义常量,但是define定义的常量可以改变
  • const

    • 修饰的变量不可变

    • 定义的常量在程序运行中会有一份拷贝

    • 编译器通常不为普通const常量分配存储空间,而是将它们存储在符号表中,使得它成为一个编译期间的常量,没有了存储与内存的操作,使得它效率高。

    • const定义的右边是不可改变的,也就是说const修饰的是它右边的部分。

    • const int kCount = 1;link
      1
      2
      3
      4
      static const int kCount = 1; //此处定义的kCount后面都不能改变值,如果改变,则报错
      static const NSString *kStr1 = @"alun1";//此处定义的kStr1可修改其值,但是修改过后他们的内存地址一样。
      static NSString const *kStr1 = @"alun1";//跟上面的定义写法不同,但是结果一样
      static NSString* const kStr2 = @"alun2";//此处定义的kStr2不能改变,否则会发生错误
  • extern

    • 修饰全局变量。
    • 变量定义在源文件的某个位置,不加extern。在其它文件加extern声明这个变量就可以使用
    • 修饰的变量没有分配内存
  • static

    • 用户不能直接方法static修饰的变量,
    • static后的语句可以使用它修饰的变量。类可以访问static修饰的变量
  • 枚举类型

    • enum声明,枚举标识符可以对应一个特定的整数值,你可以指定,或者列表中出现的标识符以整数0或者指定的数开始自+1。
      • enum direction {up, down, left = 10, right};,因为up位于首位,所以编译器就给up赋值为0, down为1,right为11
    • 定义的枚举标识符,必须与相同作用域之内的变量名不同。
    • 定义一个枚举,相当于一系列#define定义
  • typedef

    • 声明新的类型代替已有的类型名
      • char gender; ```
        1
        - ```gender a;等同于char a;
  • typedef enum

    • 定义一个数据类型,且该类型的变量值只能在enum范围内取
    • 定义的是一个数据类型。而enum定义的是一个变量
  • 分类(Category)

    • 将类的定义模块化到相关方法的组或分类中
    • 扩展现有类,不用创建子类
    • 可以添加方法,不能添加实例变量
    • 优先级高,可以覆盖原方法
    • 不可以调用super方法
    • 可以不用实现,需要调用的时候实现
  • 扩展(Extension)

    • 可以添加方法,和成员变量
    • 添加方法如果不实现会报出警告⚠️
  • 成员变量与属性

    • 属性可以生成一个带下划线的成员变量,而且还可以编译器还可以直接生成存取方法(getter和setter方法)
    • 成员变量有 private、protect、public,但是不会直接生成存取方法
  • 协议(protocol)

    • 协议是一个多个类共享的方法列表
      • 协议有很多方法,没有相应的实现,需要程序员去实现
      • 如果一个类遵守某个协议,子类也遵守
      • 协议是定义两个类的借口。
  • 代理(delegate)

    • 通过协议定义的方法代理给了实现它们
  • ·#import””和#import<>

    • 双引号导入的文件,首先先从包含源文件的头目中寻找,在从系统文件寻找。
    • <>只在特殊的系统文件中寻找,当前文件不会被寻找。
  • 预编译语句

    • #define

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      #ifdef 指定符号判断
      #define
      #endif
      #define
      #else
      #idndef
      NSLog(@"");
      #endif
    • 1
      2
      3
      #if 表达式是否为0
      #define
      #elif(#endif)
- `#undef`消除定义,即之后就不能再调用这个消除后的变量
  • Set

    • NSSet和NSArray
      • set是无序的,用来进行搜索时,比NSArray效率高,是因为NSSet有一个算法hash;例如,要存储元素A,在NSSet中,一个hash算法就可以直接找到A的位置,而存储在NSArray中,就需要遍历整个数组才能判断A在不在数组中,效率降低
    • NSIndexSet
      • 存储一系列的索引值区间
      • 可以用NSUInteger或者NSRange来表示
  • 内存管理

    • 自动垃圾收集

      • 自动检测对象是否拥有其他对象,当程序执行需要空间的时候,不再被引用的对象会被自动释放(垃圾回收)
      • 不过iOS平台并不支持垃圾回收
      • OS平台也不推荐使用垃圾回收
    • 手动引用计数和自动释放池

      • 创建对象是引用计数为1,每当创建引用到对象引用计数就会➕1.
      • 引用计数为0是,就不能调用这个对象,就需要调用NSObject的dealloc销毁。
      • NSAutoreleasePool创建的目的就是,自动释放池可以追踪需要延迟释放的对象,通过给自动释放池发送drain,释放池被清理,对象被释放
      • 当执行到autorealease末尾时,系统会释放池
      • 总结
        • retain——不销毁,使用完后release
        • 发送release对象不会被销毁,当引用计数为0时对象才会销毁。然后系统发送dealloc释放内存
        • 使用了retain、copy、mutableCopy、new、alloc的对象或者retain、copy的属性释放时需要覆盖dealloc方法,这样才能保证释放的时候释放这些实例变量
        • 应用终止时,内存中对象会全部释放
    • 自动引用计数(ARC)

      • 所有对象指针变量都是强变量啊
      • 强变量,旧的对象在赋值前被释放,新的对象被保留。强变量默认初始值为0.
      • 弱变量,建立两个变量之前的联系,防止循环引用。创建其它类型的对象变量,并允许使用不同类型的引用(弱引用)
  • 赋值

    • 简单复制
      • 数组1=数组2;如果删除数组2的某个数据,数组1也会被删除。
    • copy复制
      • 复制一份再赋值;如果删除数组2的某个数据,数组1不会改变。
  • Copy

    • 浅复制

      • 修改数组1的某个元素,数组2也会被修改。因为内存中新的数组分配了内存空间,并将单个元素赋值到新数组中,将原始数组中的元素赋值到新位置:是将引用从一个数组元素复制到另一个元素。导致两个数组中的元素都指向内存中的同一个字符串
    • 深复制

      • 会将单个元素创建自己的副本。
    • 其他类要实现copy必须实现协议,

    • 可以通过归档来实现深复制

    • 1
      2
      - archiveDataWithRootObject
      - unArchiveObjectWithData
  • 属性

    • assign(ARC/MRC)
      • 直接赋值
      • 用于简单的数据类型,因为基础数据分配在栈上,栈的内存会被系统自动处理,不会造成野指针
      • 修饰的指针指向某个对象时引用计数不被改变,不会持有对象
      • 如果修饰对象,修饰的对象分配在堆上
      • 指向的对象可能会在别处释放,指针不会被释放,成为悬挂指针
    • weak(ARC)
      • 直接赋值
      • 既不保留新值,也不释放旧值
      • 适用于NSObject对象,是一个弱引用
      • 修饰的对象释放后,指针地址会被置为nil
      • 解决循环引用
    • retain(MRC)
      • 不能修饰简单数据类型
      • 如果被修饰,会持有它指向的对象
      • 赋值时需要保留新值[newCount retain];即引用计数旧对象-1,retain新对象+1,再指向新对象
    • strong(ARC)
      • 引用计数会➕1,直接赋值
      • 复制指向同一个指针
      • 在AR取代retain
    • copy(ARC/MRC)
      • 不能修饰简单数据类型
      • 修饰的对象赋值时是拥有原有对象的拷贝
      • 需要实现协议的copyWithZone方法
  • 原子性

    • automic(默认)
      • 线程安全,销毁系统资源
      • 保证同一时间只有一个线程调用set方法,线程对属性的单一执行
      • 对生成的set方法加互斥锁@synthesize(锁对象)
    • nonatomic
      • 线程不安全
      • 不对set方法加同步锁,性能好
  • nil、Nil、NULL、NSNull

    • nil
      • 对象为空NSObject *obj = nil;
    • Nil
      • 类为空Class someClass = Nil;
    • NULL
      • 基本数据对象指针为空int *x = NULL;
    • NSNull
      • 集合对象无法包含nil作为其具体值,所有nil用一个特定的对象NSUll表示
      • 提供了一个单例表示对象的nil值+(NSNull *)null;
  • @property

    • 生成一个带下划线的成员变量和存取方法
    • 自动合成:编译器在编译时期执行,多有编辑器看不到“合成方法”