OC编程

OC语言基础.png

OC语言学习路线及重难点

  • 关键字
  • 数据类型
  • 对象存储细节
  • Xcode文档安装和自定义代码段
  • 动态数据类型id
  • 构造方法、类工厂方法
  • 类的启动过程(+load、+initialize)
  • 内存管理 MRC
  • 自动引用计数 ARC
  • Category 和 Extension
  • Block
  • Protocol
  • Foundation框架
  • Copy
  • ……

关键字

// C语言中一共有32个关键字
auto double int struct break else long switch
case enum register typedef char extern return
union const float short unsigned continue for
signed void default goto sizeof volatile do if while static
// OC中新增的关键字
@interface @implementation @end
@public @protected @private @selector
@try @catch @throw @finally
@protocol @optional @required @class
@property @synthesize @dynamic
BOOL Class SEL YES NO id self 
super nil atomic nonatomic retain assign copy block ...

数据类型

  • C语言数据类型


    C中数据类型.png
  • OC中数据类型


    OC数据类型.png

对象存储细节

对象存储细节.png

isa指针

  • 每一个对象都包含一个 isa 指针,这个指针指向当前对象所属的类
  • 调用对象方法时,此时对象会顺着内部的 isa 指针找到存储于类中的方法并执行
  • isa 是对象中的隐藏指针,指向创建这个对象的类
  • 通过 isa 指针我们可以在运行的时候知道当前对象是属于那个Class(类)的

Xcode文档安装和自定义代码段

  • 掌握在线及离线安装文档步骤;及培养阅读一手文档的习惯
  • 自定义代码:导入代码片段
    将下载好的代码片段拷贝到:/Users/litongde/Library/Developer/Xcode/UserData/CodeSnippets

动态数据类型id

  • id == NSObject * 万能指针
    NSobject * 是一个静态数据类型
    id 是一个动态数据类型
  • 通过静态数据类型定义变量,不能调用子类特有方法
  • 通过动态数据类型定义变量,可以调用子类特有方法
  • 通过动态数据类型定义变量,可以调用私有方法
  • 弊端:由于动态数据类型可以调用任意方法,所以可能会调用不属于自己的方法,导致运行时报错

构造方法、类工厂方法

// 构造方法
- (instancetype)init {
    if (self = [super init]) {
        // Initialize self.
    }
    return self;
}
// 类工厂方法
+ (instancetype)类名称
{
    // 谁调用这个方法,self就代表谁
    // 注意:写类方法创建初始化对象,写self不要直接写类名
    return  [[self alloc] init];
}

类的启动过程(+load、+initialize)

+load方法

  • 只要程序启动就会将所有类的代码加载到内存中,放到代码区
  • load 方法会在当前类被加载到内存的时候调用,有且仅会调用一次
  • 如果存在继承关系,会先调用父类的 load 方法,再调用子类的 load 方法,跟 initialize 一样

+initialize方法

  • 当前类第一次被使用的时候就会调用(创建类对象的时候)
  • initialize 方法在整个程序的运行过程中只会被调用一次
  • initialize 用于对某一个类进行一次性初始化

内存管理 MRC

// set方法内存管理 例
- (void)setRoom:(Room *)room
{
    // 避免过度释放
    if (room != _room) {
        // 对当前正在使用的房间(旧房间)做一次release
        [_room release];
        // 对新房间做一次retain操作
        _room = [room retain];
    }
}
// dealloc方法的内存管理 例
- (void)dealloc
{
    [_room release];
    [super dealloc];
}

@property参数

  1. 控制set方法的内存管理
  • retain:release旧值,retain新值(用于OC对象)
  • assign:直接赋值,不做任何内存管理(默认,用于非OC对象类型)
  • copy:release旧值,copy新值(一般用于NSString *)
  1. 控制需不需要生成set方法
  • readwrite:同时生成set方法和get方法(默认)
  • readonly:只会生成get方法
  1. 多线程管理
  • atomic:性能低(默认)
  • nonatomic:性能高
  1. 控制set方法和get方法的名称
  • setter:设置set方法的名称,一定有个冒号:
  • getter:设置get方法的名称

ARC下@property参数

  • strong:用于OC对象, 相当于MRC中的retain
  • weak:用于OC对象, 相当于MRC中的assign
  • assign:用于基本数据类型, 跟MRC中的assign一样

autorelease使用

  • autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
  • 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
  • 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
@autoreleasepool
{   // 创建一个自动释放池
    Person *p = [[Person new] autorelease];
}   // 销毁自动释放池(会给池子中所有对象发送一条release消息)

自动引用计数ARC

ARC的判断原则

  • 只要还有一个强指针变量指向对象,对象就会保持在内存中

强指针

  • __strong 修饰的指针,默认所有指针变量都是强指针

弱指针

  • __weak 修饰的指针

Category 和 Extension

category分类 \ 类别 \ 类目 (一般叫分类)

  • 作用:可以在不修改原来类的基础上, 为这个类扩充一些方法
  • 注意:分类只能增加方法, 不能增加成员变量
  • 注意:分类中写property只会生成方法声明
  • 注意:分类可以访问原来类中的成员变量
  • 注意:调用顺序为 分类——原来类——父类

类扩展(Class Extension) 是Category的一个特例

  • 可以为某个类扩充一些私有的成员变量和方法。写在.m文件中
// 类扩展书写格式
// 对比分类, 就少了一个分类名称,因此也有人称它为”匿名分类”
@interface 类名 ()
@end

Block

Block是iOS中一种比较特殊的数据类型

// Block的定义格式
返回值类型 (^block变量名)(形参列表) = ^(形参列表) {
};

// 调用Block
block变量名(实参);

Block注意事项

  • block 内部可以访问 block 外部的变量
  • block 内部也可以定义和 block 外部的同名的变量(局部变量),此时局部变量会暂时屏蔽外部
  • 默认情况下, block 内部不能修改外面的局部变量,是值传递
  • block 内部可以修改使用__block修饰的局部变量

Block是存储在堆中还是栈中

  • 默认 block 存储在栈中,如果对 block 进行一次 copy 操作,block 会转移到堆中
  • block 在栈中,block 中访问外部对象,不会对对象进行 retain 操作
  • block 在堆中,block 中访问外部对象,会对外界对象进行一次 retain

Protocol

  • Protocol的定义和遵守协议
// Protocol的定义
@protocol 协议名称
@required // 如果遵守协议的类不实现会报警告
@optional // 如果遵守协议的类不实现不会报警告
@end

// 类遵守协议
@interface 类名 : 父类 <协议名称1, 协议名称2,…>
@end
  • Protocol和继承区别
    继承之后默认就有实现, 而 protocol 只有声明没有实现
    相同类型的类可以使用继承, 但是不同类型的类只能使用protocol
    protocol可以用于存储方法的声明, 可以将多个类中共同的方法抽取出来, 以后让这些类遵守协议即可

Foundation框架

Foundation框架提供了非常多好用的类, 比如

/**
 1、NSString 字符串
 NSString 比较
 -  (BOOL)isEqualToString:(NSString *)aString 比较的是内容
 - stingA == stringB 比较的是地址
 - NSURL URL的全称是Uniform Resource Locator(统一资源定位符)
 */
NSString *str = @"ltd"; // 常量区中的字符串只要内容一致, 不会重复创建

/**
 2、NSMutableString 可变字符串
 */
NSMutableString *strM = [NSMutableString string];

/**
 3、NSArray 数组
 */
NSArray *arr = @[@"Jack", @"Rose", @"Jim"];

/**
 4、NSMutableArray 可变数组
 */
NSMutableArray *arrM = [NSMutableArray array];

/**
 5、NSDictionary 字典
 */
NSDictionary *dict = @{@"name":@"lnj", @"phone":@"18682057731", @"address":@"天朝"};

/**
 6、NSMutableDictionary 可变字典
 */

/**
 Q:NSDictionary 和 NSArray 对比
 - NSArray是有序的,NSDictionary是无序的
 - NSArray是通过下标访问元素,NSDictionary是通过key访问元素
 */

/**
 7、NSNumber 
 NSNumber可以将基本数据类型包装成对象,这样就可以间接将基本数据类型存进NSArray\NSDictionary中
 */
NSNumber *num = @10;

/**
 8、NSValue
 NSNumber是NSValue的子类, 但NSNumber只能包装数字类型
 NSValue可以包装任意值, 可以用NSValue将结构体包装后,加入NSArray\NSDictionary中

 + (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
 + value参数 : 所包装数据的地址
 + type参数 : 用来描述这个数据类型的字符串, 用@encode指令来生成
 */

/**
 9、NSDate 时间
 */
// ————————————基本使用————————————
NSDate *now = [NSDate date];
// 设置转换后的目标日期时区
NSTimeZone *zone = [NSTimeZone systemTimeZone];
// 得到源日期与世界标准时间的偏移量
NSInteger interval = [zone secondsFromGMTForDate: date];
// 在当前时间基础上追加时区差值
now = [now dateByAddingTimeInterval:interval];

// ————————————格式化日期————————————
 // 创建时间
NSDate *now = [NSDate date];
// 创建时间格式化
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// 指定格式
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
// 格式化时间
NSString *str = [formatter stringFromDate:now];

// ————————————日历对象————————————
 // 1.确定时间
NSString *time1 = @"2015-06-23 12:18:15";
NSString *time2 = @"2015-06-28 10:10:10";
// 2.将时间转换为date
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate *date1 = [formatter dateFromString:time1];
NSDate *date2 = [formatter dateFromString:time2];
// 3.创建日历
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit type = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
// 4.利用日历对象比较两个时间的差值
NSDateComponents *cmps = [calendar components:type fromDate:date1 toDate:date2 options:0];
// 5.输出结果
NSLog(@"两个时间相差%ld年%ld月%ld日%ld小时%ld分钟%ld秒", cmps.year, cmps.month, cmps.day, cmps.hour, cmps.minute, cmps.second);

/**
 10、NSFileManager 
 */
NSFileManager *manager = [NSFileManager defaultManager];

Foundation框架常见的结构体

  • NSPointCGPoint
  • NSSizeCGSize
  • NSRectCGRect

Copy

特点

  • 修改源对象的属性和行为,不会影响副本对象
  • 修改副本对象的属性和行为,不会影响源对象

使用

  • 一个对象可以调用 copymutableCopy 方法来创建一个副本对象
  • copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
  • mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)

前提

  • copy : 需要遵守 NSCopying 协议,实现 copyWithZone: 方法
  • mutableCopy : 需要遵守 NSMutableCopying 协议,实现 mutableCopyWithZone: 方法

深复制和浅复制

  • 深复制本质是 产生了新的对象、浅复制本质是 没有产生新的对象
  • 只有源对象和副本对象都不可变时,才是 浅复制,其它都是 深复制

@property中的copy的作用

  • 防止外界修改内部的值
  • 防止 block 中使用的外部对象已经被释放

注意:copy block 之后引发循环引用
如果对象中 block 又用到了对象自己,为了避免内存泄漏,应将对象修饰为__block

你可能感兴趣的:(OC编程)