1. 思考1个问题. 要表示1个坐标.需要两个数据来表示. 1个是x坐标 1个是y坐标. x坐标和y左边联合起来表示 界面上的1点. 1个坐标需要两个数据表示. 结构体和类的区别: 1). 结构体是由多个小变量组合而成的. 结构体中只能有属性. 对象中既有小变量,还可以有方法. 对象中即可有有属性也可以方法. 2). 结构体变量是存储在栈区. 对象是存储在堆区的. 在内存中栈区相对较小.但是栈区的数据访问效率要高. 堆区相对较大,但是堆区的数据访问效率相对较低. 3). 虽然栈区的空间访问效率相对较块,但是千万不要把所有的数据都一股脑的全存储在栈区 因为栈区空间较小,如果都存储在栈区 反而会影响性能. 4). 什么时候使用类. 如果封装的这个数据 既有属性也有方法, 只能使用类. 如果封装的数据只有属性. 如果这是1个轻量级的数据,就使用结构体. 属性很少. 如果这是1个重量级的数据 就使用类. 属性很多. 轻量级使用结构体. 重量级使用类. 很明显要保存1个点.使用结构体是最合适的 因为它只有两个属性. ------ 幸运的是,如果我们真的要去保存1个控件的坐标 我们不需要去自己定义结构体类型. 因为这个结构体Foundation框架中已经定义好了.我们要用直接声明变量就可以了. CGPoint这是它的定义. struct CGPoint { CGFloat x; CGFloat y; }; typedef struct CGPoint CGPoint; 这个结构体就是来表示控件的坐标的. CGFloat 就是double typedef CGPoint NSPoint; CGPoint完全等价于NSPoint. CGPoint初始化的方式. 1). 先声明CGPoint变量 然后再初始化属性. CGPoint p1; p1.x = 10; p1.y = 20; 2). CGPoint p1 = {10,20}; 3). CGPoint p1 = {.x = 20, .y = 30}; 4). 使用系统自带的函数来快速的创建CGPoint变量. CGPoint p1 = CGPointMake(10, 20); CGPoint p1 = NSMakePoint(10, 20); 5). 使用函数将CGpoint变量转换为字符串. NSStringFromPoint(); 2. 思考: 请定义1个变量来保存1个控件的尺寸. 如果我们要保存1个控件的尺寸,而1个控件的尺寸是由1个宽度和高度组合而成的. 使用结构体来最合适. CGSize 这是它的定义. struct CGSize { CGFloat width; //宽度 CGFloat height; //高度 }; typedef struct CGSize CGSize; typedef CGSize NSSize; NSSize完全等价于CGSize 这个结构体的作用: 保存1个控件的尺寸. ----CGSize的初始化------- CGSize s1 = CGSizeMake(100, 200); CGSize s2 = NSMakeSize(100, 200); 将CGSize结构体变量转换为字符串. NSLog(@"%@",NSStringFromSize(s1) 3. CGRect. 这是它的定义. struct CGRect { CGPoint origin; //代表控件的坐标 CGSize size; //控件的尺寸. }; typedef struct CGRect CGRect; 这个CGRect类型的变量 是来保存1个控件的坐标和尺寸. typedef CGRect NSRect; NSRect和CGRect完全等价. ----初始化----- CGRect r1 = CGRectMake(10, 20, 100, 200); CGRect r2 = NSMakeRect(10, 20, 100, 200); 将CGRect变量转换为字符串. NSLog(@"%@", NSStringFromRect(r1)); 平时使用我们还是使用CGXX 虽然NSXX效果一样.
1. 集合中只能存储OC对象.无法存储基本数据类型. 基本数据类型就无法存储. 但是我就是要把基本数据类型存储到集合中 怎么办? 想法: 先把基本数据类型包装到1个OC对象中. 然后再将这个OC对象存储到集合中. 幸运的是: 包装基本数据的类型的那个类.Foundation框架已经写好了. NSNumber 存储基本数据类型到集合中的原理: 1). 先将基本数据类型存储到NSNumber对象中. 2). 然后再将NSNumer对象存储到集合中. 3). 从集合中取值元素的值 取出来是1个NSNumebr对象. 真正的数据是存储在这个对象里的. 注意: 要包装什么类型的数据,在使用类方法包装的时候要调用对应的方法. 从NSNumber取值的时候 你包装的是什么类型的数据在其中,就要调用对应的 xxxValue方法. 2. 简要创建NSNumber对象的形式. @20; 记住,这不是1个整型的20 而是1个NSNumber对象.这个对象中包装的是整型的20 注意: 如果是1个变量.就需要使用小括弧括一下. int num = 10; NSNumber *num1 = @(num);
NSValue 集合中是无法存储基本数据类型的.包括结构体 只能存储OC对象. NSValue来包装结构体数据的以便将其间接的存储到集合中.
NSDate: 处理日期与时间的1个类.
1).可以得到当前系统的时间. 直接创建1个NSDate对象,这个对象中存储的就是当前系统的格林威治时间. NSDate *date = [NSDate date]; 2).默认输出的时间格式: 2020-03-28 07:47:37 +0000 2020/3/28 7:47:37 自定义日期的输出格式. NSDate *date = [NSDate date]; //1.先创建1个日期格式化对象.这个对象的功能,可以按照指定的格式将1个日期转换为1个字符串. NSDateFormatter *formatter = [NSDateFormatter new]; //2.指定要转换的格式. //y 年 写4个y 表示用4位来表示年. //M 月 //d 天 //h 12小时制的小时. //H 24小时制的小时. //m 分钟 //s 秒 //你完全可以自定义这个格式. formatter.dateFormat = @"yy年M月dd日 hh点mm分ss秒"; //3.按照指定的格式将日期转换为指定的格式的字符串. NSString *str = [formatter stringFromDate:date]; 用这种方式转换以后,会自动的转换为当前时区的时间. 3). 将字符串转为为日期对象. NSString *str = @"2020/12/12 13:12:12"; NSDateFormatter *formatter = [NSDateFormatter new]; formatter.dateFormat = @"yyyy/MM/dd HH:mm:ss"; NSDate *date = [formatter dateFromString:str]; NSLog(@"date = %@",date);
2. 在当前时间的基础之上加指定的秒数以后是多久. + (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs 3. 计算两个时间之差. - (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate; 4. 得到日期对象的各个部分. 1). 使用NSDateFormatter来拿到每一部分. 2). 另外一种更加复杂的方法.
深拷贝与浅拷贝
1. 结论: 无论在ARC模式下,还是在MRC模式下.如果1个对象的属性是NSString类型的. @property参数.不要写retain、strong、weak. 而是用copy. 强调: 只有当属性的类型是NSString的时候,@property参数才使用copy 2. copy是1个方法.定义在NSObject类中. 所以所有的OC类都有这个方法,包括NSString. copy方法的作用: 复制1个对象.重新来1个一模一样的对象. 对象的属性的值相同. 测试1下 字符串的copy方法. NSString --> copy --> NSString 这个时候,没有产生新对象.像这样的拷贝叫做浅拷贝. 没有产生新对象,而是直接将原来那个对象的地址返回. NSMutableString -> copy -> NSString 这个时候,有新对象的产生,像这样的拷贝叫做深拷贝. 有产生新对象. mutableCopy方法.也是拷贝对象. NSString -> mutableCopy --> NSMutableString 深拷贝. NSMutableString -> mutableCopy -> NSMutableString 深拷贝. 总结: 只有对象是NSString的时候 copy 才是浅拷贝. 其他都是深拷贝. copy 出来的都是不可变字符串 mutableCopy出来的都是可变字符串.
单例设计模式. 单例:单个实例. 单个对象. 1个类的对象,无论在何时创建,无论创建多少次.创建出来的对象都是同1个对象. 2. 创建对象的方法. + alloc 方法 这个方法才是真正的在内存中申请空间创建对象. 其实这个方法什么事情都没有做. 只是调用另外1个 + allocWithZone:方法. 正儿八经的在内存中申请空间创建对象的事情 其实是+ allocWithZone:方法. alloc方法的内部只是调用了+ allocWithZone:方法.
3. 如何实现单例模式. + (instancetype)allocWithZone:(struct _NSZone *)zone { static id instance = nil; if(instance == nil) { instance = [super allocWithZone:zone]; } return instance; } zone: 参数是没有任何意义的. 4. 单例的规范. 1). 如果我们的类设计为了单例模式. 要求为这个类提供1个类方法 来快速的得到这个单例对象. 这个类方法的名称的规范: defaultXXXX;
sharedXXXX; 5. 有什么用? 1). 单例的特点 无论何时、无论何地、无论创建多少次,得到的都是同1个对象. 意味着这个单例对象中的属性的值被共享. 2). 如果有一些数据.程序中的所有的地方都要使用. 如何共享这个数据? 游戏面板的宽度和高度. width = 800; height = 600; 当有一些数据需要共享给别的类的时候,就可以把这些数据存在单例对象中.
|