爬爬爬之路:OC语言(七) NSDate , 协议和代理

来源:互联网 发布:家具绘图软件 编辑:程序博客网 时间:2024/06/08 01:07

*NSDate

1. 初始化方法有:

                          // 创建一个距离现在时间n秒后的日期(昨天加上 -)+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;                          // 创建一个距2001年1月1日n秒后的日期+ (instancetype)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti;                          // 创建一个距1970年1月1日n秒后的日期+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;

比如创建一个昨天的日期:

NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-24*3600]; // 昨天这此时的时间

2. 然而最常用的初始化方法还是:

+ (instancetype)date;

  • 本方法创建的结果直接打印输出的是当前0时区(格林威治)标准时间的具体时间
    但实际创建出来的结果保存的是当地时间 只是输出的时候被转化成了格林威治时间

  • 以中国为例, 北京时间为东八区的时间, 也就是说date需要加上8小时的时间才是目前的北京时间

3. 常用的方法

- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;
比较两个时间的时间差


NSDateFormatter

1. 继承自NSFormatter(一个抽象类)

  • p.s. 抽象类的特点: 抽象类本身不实现具体功能 具体的功能由其子类去实现

2. 日期格式类NSDateFormatter

日期格式类的作用是创建一个格式, 将某个对象按照给定的格式转化成另一个对象

1. 常用方法:

```                            // 将日期按照NSDateFormatter格式转化为字符串- (NSString *)stringFromDate:(NSDate *)date;                              // 将字符串按照NSDateFormatter格式转化为日期- (NSDate *)dateFromString:(NSString *)string; ```

2. 初始化方法

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

3. 格式设置方法

            // 通过dateFormat的set方法, 给格式设定指定格式 @property (copy) NSString *dateFormat;  

格式如: y表示年, M表示月份, d 表示天 H表示24小时制的小时 h12小时制的小时 m表示分钟 s表示秒
这里的y M d等类似于占位符 一个字母只能替换成一个数字, 比如2015表示年份, 是4位的 得用yyyy表示
比如表示 2015年11月11日 20-00-00
格式要写成 yyyy年MM月dd日 HH-mm-ss

4. 例题

将当前时间用 xxxx年xx月xx日 xx-xx-xx的格式输出

NSDate *date = [NSDate date];    // 根据自定义格式, 输出时间NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    // 添加一个格式[formatter setDateFormat:@"yyyy年MM月dd日 HH-mm-ss"];NSString *dateString = [formatter stringFromDate:date];NSLog(@"%@", dateString);

结果输出的是现在的当前时间

但是值得注意的是:

NSDate *newDate = [formatter dateFromString:dateString];NSLog(@"%@", newDate);

由上段代码直接转化回日期格式输出, 结果输出的是格林威治时间.
验证了之前的说法, NSDate类创建出来的对象是当前时间, 而调用日期累的description方法, 会被自动减去时区差的秒数, 被转化成格林威治时间.

  • 注意在使用NSDate的description方法的时候, 会自动把小时减去时区差. 通常我们需要在调用NSDate的description方法的时候, 添上一个时区差的秒数

获取时区类NSTimeZone

1. 常用初始化方法

NSTimeZone *zone = [NSTimeZone systemTimeZone];
输出zone
NSLog(@"%@", zone);
获取的结果当前所在的时区的地球位置, 已经和0时区的秒数差

2. 用法

将字符串”2012.04.01 20:21:56”转化成NSDate类输出
值得注意的是, 当输出NSDate对象的时候, 系统会自动将NSDate的转化成格林威治时间, 所以将字符串里保存的时间 直接设置成格林威治所在的0时区的时间, 输出的时候就不会被系统自动减去时区差转化的秒数.

NSString *time = @"2012.04.01 20:21:56";  // 将时间用字符串保存[formatter2 setDateFormat:@"yyyy.MM.dd HH:mm:ss"]; // 设置格式                                            // 将时区设置成0时区NSTimeZone *zone = [NSTimeZone timeZoneForSecondsFromGMT:0]; [formatter setTimeZone:zone];                                NSDate *dateNew = [formatter dateFromString:time];                         // 此时的dateNew存放的是0时区的2012.04.01 20:21:56NSLog(@"%@", dateNew2);  // 由于时区相同, 此时输出的就是2012.04.01 20:21:56

Category类目

  1. 添加方法: Xcode工程下按Commond + n 选择Objective-C File, 选择category

  2. 作用: 给系统添加自定义的方法

  3. 特点: 可以给看不见实现的系统类 添加方法 并且添加的方法 使用系统对象或者系统类的类名直接调用

类目中添加方法 相当于直接添加到类当中, 是可以被该系统类的子类继承的(包括自定义的继承该系统的自定义类)

切记: 只能添加方法 不能添加实例变量
这里写图片描述


Extension延展

只能写私有变量和方法声明, 只能在本类中使用
在类中用self调用
创建方法:

  1. 添加方法: Xcode工程下按Commond + n 选择Objective-C File, 选择Extension
  2. 直接在在需要延展的类中在@implementation语句和#import语句之间的位置输入@i根据提示选择@interface-extension - Objective-C Class Extension即可

通常情况下选择方法2创建类的延展

这里写图片描述

延展的特点:

  1. 声明的是私有的方法和实例变量
  2. 一定要给有源代码的类创建延展, 否则毫无意义
  3. 并且声明的私有方法需要在源类的.m文件中实现

*Protocol协议 和 delegate代理

1. 协议和代理的存在, 是为了实现类与类之间的低耦合性

协议相当于一个契约. 两个类对象之间若存在委托关系(对象A需要让别人帮忙做某件事, 而B签订了这个契约, 就需要B去帮助A完成这件事.A和B之间就存在A委托B的关系), 比如说对象A中的某个方法需要委托另一个对象去完成某个或者某些步骤, 但是又不确定具体由哪个对象来完成. 这时候就可以将这些步骤完成的方法声明在协议里, 等到某个可以签订这个协议的对象B被创建出来的时候, A确定由这个对象B来完成后续步骤, 就可以将B设置为自己的代理人. 而协议中的方法分为必须完成和选择型完成两种, 分别用@required和@optional修饰. @required要求被代理人的方法实现中必须得实现这个方法(其实如果没有写这个方法的实现的话, 系统会提示黄警报, 但是不会报错). 若是程序需要调用到对象A中的某些方法, 并且这些方法的后续步骤是需要被代理人B实现的, 而此时若对象B的类中没有该方法实现. 程序会崩溃(除非在A中的方法有安全保护措施). 下面会通过代码例子来介绍.

2. 代理和协议是依托的

在协议中, 用@required 修饰的方法是使用这个协议的被代理人必须做的 @optional是可以选择性做的

比如说, 在某个类里的某个方法, 需要调用另一个类完成相应的后续操作. 而这个操作可以是不同的类都能完成的. 这时候就可以把后续操作交给协议, 在协议里声明. 在本类中声明一个代理, 用来完成这个操作.

3. 如何定义和使用协议

总的来说, 设置并实现一个完整的代理过程需要7个准备步骤

  1. 先创建一个协议, 协议中根据需要确定哪些代理方法是必须的, 哪些是选择执行的

  2. 创建一个类B遵守该协议

  3. 在类中实现协议需要实现的方法

  4. 在代理类A里添加代理对象为实例变量(谁需要代理, 就在那个类里创建声明代理的实例变量)

  5. 添加设置代理对象的方法(通过set方法)

  6. 让代理人B调用协议中的对应方法

  7. A中判断代理B有没有实现对应的代理方法(安全措施处理手段)

4. 例题

定义一个女生(Girl)类: 方法有:购物shopping, 肚子饿hungry, 衣服脏dirty 其中shopping方法需要代理帮她挣钱, 肚子饿需要代理人帮她做饭, 衣服脏需要代理人帮她洗衣服.
通过一个结婚协议(MarryProtocol) 寻找代理人. 要求代理人可以完成 挣钱, 做饭, 洗衣服. 其中挣钱方法(makeMoney)是必须的, 做饭(cook), 洗衣服(washCloth)是可以选择的
定义一个男生(Boy)类: 用来接收协议, 并完成协议要求的方法.

// 协议类, 只有一个.h文件// MarryProtocol.h#import <Foundation/Foundation.h>@protocol MarryProtocol <NSObject>// 如何遵守协议?// 用尖括号<要遵守的协议>// 协议中声明的是协议方法// 如果没有明确的要求 默认协议中的方法 是都要实现的@required      // 必须要实现的(也是默认的)// 挣钱- (void)makeMoney;@optional      // 可选择性实现的// 做饭- (void)cook;- (void)washCloth;// 协议中只写方法的声明  使用这份协议的类中写实现@end
// Boy类// Boy.h#import <Foundation/Foundation.h>#import "MarryProtocol.h"@interface Boy : NSObject <MarryProtocol>   // 在父类名后 用<协议名> 表示接收代理                            // 声明可以不需要写也不可以写协议中的方法@end// Boy.m#import "Boy.h"@implementation Boy// 实现协议中的方法- (void)makeMoney {     // 要求必须实现的    NSLog(@"赚钱");}- (void)cook {          // 选择性实现的方法    NSLog(@"煮饭");}- (void)washCloth {     // 可以选择不实现    NSLog(@"洗衣服");}@end
// Girl类// Girl.h#import <Foundation/Foundation.h>#import "MarryProtocol.h”                // 注意, 这里不引入Boy的头文件, 因为代理人可以不仅仅是Boy类对象@interface Girl : NSObject{     // 声明一个代理对象 作为实例变量     // 代理对象必须是遵守协议的对象     // id表示代理人的类型不是固定的, id<协议名> 表示是接收了协议的对象类型作为代理人    id<MarryProtocol> _delegate; // 代理对象的命名规范 代理人统一命名为delegate.}// 添加设置代理的方法- (void)setDelegate:(id<MarryProtocol>)delegate;- (void)shopping;     // 购物方法- (void)hungry;       // 肚子饿方法- (void)dirty;        // 衣服脏方法@end// Girl.m#import "Girl.h"@implementation Girl- (void)setDelegate:(id<MarryProtocol>)delegate { // 和普通的实例变量set方法相同    _delegate = delegate;}- (void)shopping {                // 需要代理人完成协议中的makeMoney方法    NSLog(@"购物");    if ([_delegate respondsToSelector:@selector(makeMoney)]) {        [_delegate makeMoney];    } else {        NSLog(@"这个懒鬼没赚钱 买不了了");    }}- (void)hungry {    NSLog(@"饿");    // 需要代理人去做饭 既需要代理实现做饭的方法  需要代理的对象实现协议中的方法(因为代理对象实现了代理方法)    if ([_delegate respondsToSelector:@selector(cook)]) {        [_delegate cook];    } else {        NSLog(@"这个懒鬼不做饭");    }}- (void)dirty {    NSLog(@"脏");    if ([_delegate respondsToSelector:@selector(washCloth)]) {        [_delegate washCloth];    } else {        NSLog(@"这个懒鬼不洗衣服");    }}@end

若要同时遵守多个协议, 只需要在尖括号里加个逗号再写下一个遵守的协议名. 写法如:
@interface 类名 : 父类名 <Protocol1, Protocol2, ...>
子类继承父类, 子类在不需要写遵守协议的同时还是会继承了父类遵守的协议.

0 0
原创粉丝点击