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;
当有一些数据需要共享给别的类的时候,就可以把这些数据存在单例对象中.
| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |