OC知识点回顾
- 面向对象三大支柱
封装:就是把相关的数据和代码结合成一个有机的整体,形成数据和操作代码的封装体,对外只提供一个可以控制的接口,内部大部分的实现细节对外隐蔽,达到对数据访问权的合理控制。
继承:从已有的类创建新类的过程,提供继承信息的称为父类,得到继承信息的称为子类,之类和父类之间是IS-A关系。
多态:不同结构的对象可以以各自不同的方式响应同一个消息,或者或同一个消息可以根据发送消息的对象的不同采用多种不同的操作行为。重写是对父类的方法给出新的实现版本,重写是实现多态性的重要步骤。由于不同的子类对父类方法进行重写时可以给出各自的实现版本,因此他们收到相同的消息时会表现出不同的行为,这就是所谓的多态。有了多态我们可以通过父类型的指针指向子类,然后向子类对象发出消息,父类指针可以指向任意子类对象。
CDCircle *circle = [CDCircle circleWithRadius:10 x:0 y:0];
CDRect *rect = [CDRect rectWithWidth:10 heigth:20 x:0 y:0];
CDDBTriangle *tri = [CDDBTriangle triangleWithEdge:5 x:0 y:0];
NSArray *array = @[circle, rect, tri];
// 定义一个对象指针类型的时候尽可能使用父类型的指针
// 因为父类型的指针可以指向子类对象(上转型)
// 使用父类型的指针可以让程序的通用性更强
for (CDShape *tempShape in array) {
// 同样的指针 调用同样的方法(发同样的消息)
// 但是绘制出了不同的图形 这就是多态
// OC的消息机制是: 不看指针看对象
[tempShape draw];
NSLog(@"周长: %f", tempShape.perimeter);
NSLog(@"面积: %f", tempShape.area);
}```
- 面向对象的编程原则
- 单一职责原则(SRP): 设计一个类应该只围绕一个主题或中心思想服务;设计一个方法应该只做好一件事情。
- 开闭原则(OCP): 好的软件实体只接受扩展不接受修改。抽象是关键,用继承结构封装可变性(隔离程序中不同的可变因素)。
- 依赖倒转原则(DIP): 要面向抽象编程不要面向实现编程。声明指针变量的类型、方法的参数类型、方法的返回类型时尽可能使用父类型指针或协议指针(id<协议>),不要使用具体类型(子类型)指针。
- 里氏替换原则(LSP): 任何时候用子类对象替换父类型对象都是可以的,但是反过来通常是不成立的。子类能力比父类能力更多,用能力多的替换能力少的当然可以,反之未必成立。
- 接口隔离原则(ISP): 协议小而专,不能大而全。不能够将不相关的方法组织到一个协议中,这样会模糊协议所表示的角色。
- 合成聚合复用原则(CARP) : 优先考虑用强关联关系复用代码而不是使用继承。- 方法的命名应当使用驼峰标识(Camel Notation)。
- C语言字符串(字符数组)的赋值不能使用= 要使用字符串拷贝函数
strcpy(name, _name);
// 1. 用符号常量替换字面常量
// 2. 用const定义常量而不是用宏定义常量
static const double FENCE_PRICE = 25.5; ```
- 类方法
跟类的对象状态无关的方法,它属于类不属于对象,类方法的调用只能通过类名来调,类方法不能使用成员变量(成员变量属于某个特定的对象)。 - Class也是一种类型
Class catClass = [CDCat class]; CDCat *cat = [[catClass alloc] init]; [cat catchTheMouse];
Class dogClass = NSClassFromString(@"CDDog"); CDDog *dog = [[dogClass alloc] init]; [dog keepTheDoor];
for (CDPerson *tempPerson in persons) {
[tempPerson eat:@"盒饭"];
[tempPerson play:@"麻将"];
// RTTI
// (运行时类型识别 RunTime Type Identification)
if ([tempPerson isKindOfClass:[CDStudent class]]) {
[tempPerson performSelector:@selector(study:) withObject:@"C语言"];
}
else if ([tempPerson isKindOfClass:[CDTeacher class]]) {
[tempPerson performSelector:@selector(teach:) withObject:@"HTML网页设计"];
}
}```
SEL是一种类型,它是代表对象方法的类型,它的值相当于是一个对象方法的标识符,可以通过此标识符调用对象的方法,类似C语言中指向函数的指针,可以通过扩展指令@selector获得方法的选择器。
void bar(id obj, SEL sel, id param) {
// 给对象发由选择器指定的消息(执行选择器)
// 通过NSObject的respondsToSelector:方法可以判定对象
// 是否能够接收指定的消息(对选择做出响应)
if ([obj respondsToSelector:sel]) {
// 如果对象不能接收指定的消息 程序会崩溃
// 上面的if判断可以确保对象不会执行无法识别的选择器
pragma clang diagnostic push
pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[obj performSelector:sel withObject:param];
pragma clang diagnostic pop
}
}```
- 单例模式
避免重复创建对象,减少对象状态混乱或者内存耗费问题。要点:1.阻止使用构造方法初始化对象。2.使用类方法向外界提供该类的唯一实例。
-(instancetype) init {
@throw [NSException exceptionWithName:@"初始化对象异常" reason:@"不允许通过初始化方法创建对象" userInfo:nil];
}
+(instancetype) sharedManager {
static CDBookManager *sharedManager = nil;
// 同步保护 (只允许一个线程进入下面的代码块执行 如果有多个线程 其他线程需要排队等待之前进入的线程离开同步块以后才能进入同步块 这样即便在多线程环境下也能保证该类只能创建出一个对象)
@synchronized (self) {
if (!sharedManager) {
sharedManager = [[self alloc] initPrivate];
}
}
return sharedManager;
}```
- 枚举
//typedef enum { UP, DOWN, LEFT, RIGHT } Direction;
typedef NS_ENUM(NSUInteger, Direction) {
UP = 1 << 0,
DOWN = 1 << 1,
LEFT = 1 << 2,
RIGHT = 1 << 3
};
- NSEnumerator
// 迭代器遍历
NSEnumerator *en = [array3 reverseObjectEnumerator];
NSString *str = nil;
while(str = [en nextObject]) {
NSLog(@"%@", str); }```
- 数组排序
- 方法1:sortUsingDescriptors (使用排序描述符对象描述排序规则)
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:@"xyz" ascending:YES];
NSArray *descArray = [[NSArray alloc] initWithObjects:&desc count: 1];
[mArray sortUsingDescriptors:descArray]; ```
Example:
// 通过指定排序描述符对象对玩家手上的扑克进行排序
NSSortDescriptor *suiteDesc = [[NSSortDescriptor alloc] initWithKey:@"suite" ascending:YES];
NSSortDescriptor *faceDesc = [[NSSortDescriptor alloc] initWithKey:@"face" ascending:YES];
// 按照数组的书写顺序 suiteDesc是第一排序关键字 faceDesc是第二排序关键字 也就是说先比花色 花色相同再比点数
[cardsOnHand sortUsingDescriptors:@[suiteDesc, faceDesc]];```
- 方法2:sortUsingComparator (使用block语法将比较规则传入排序方法中)
NSComparator comp = ^(id obj1, id obj2) {
if(obj1.prop == obj2.prop) {
return NSOrderedSame;
}
else {
return book1.prop < book2.prop? NSOrderedAscending : NSOrderedDescending;
}
};
[mArray sortUsingComparator:comp]; ```
- 方法3:sortUsingSelector (通过为对象提供比较方法支持排序)
-(NSComparisonResult) compare:(CDBook *) other {
if(self.counter - other.counter == 0) {
return NSOrderedSame;
}
else {
return self.counter > other.counter? NSOrderedAscending : NSOrderedDescending;
}
}```
NSArray *array = @[@"quick", @"fuck", @"duck", @"earthquake"];
// NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(compare:)];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return [obj1 compare:obj2];
}];
NSArray *array = @[@10, @5, @99, @36, @20];
// NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(compare:)];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
NSArray *array = @[
[[CDPerson alloc] initWithName:@"王大锤" age:24],
[[CDPerson alloc] initWithName:@"骆昊" age:35],
[[CDPerson alloc] initWithName:@"李小龙" age:32],
[[CDPerson alloc] initWithName:@"张三丰" age:120]];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(CDPerson *obj1, CDPerson *obj2) {
if (obj1.age == obj2.age) {
return NSOrderedSame;
}
else {
return obj1.age < obj2.age? NSOrderedAscending : NSOrderedDescending;
}
}];
for (CDPerson *tempPerson in sortedArray) {
NSLog(@"%@", tempPerson);
}
- Category与Extension
Category :类别相当于是我们给类打的一个补丁,通过这个补丁可以扩展类的能力。
Extension:匿名类别(类扩展),通过匿名类别来声明私有化的成员变量(也可以声明在实现部分);前置声明私有化的成员方法;声明私有化的属性。 - 基本数据类型不能被添加到数组和字典等Objective-C 专有的数据结构中,也不能通过类别为其增强实现。
- NSNumber 常用方法:
-xxxValue
- (NSNumber )initWithXxx:(xxx)value
+(NSNumber )numberWithXxx:(xxx)value
-(NSComparisonResult)compare:(NSNumber )aNumber
-(BOOL)isEqualToNumber:(NSNumber )aNumber
- NSValue是NSNumber的父类,可以存储任何类型的数据,包括符合数据类型(数组,指针,结构体)甚至对象。
- NSTimeZone
+(NSTimeZone )systemTimeZone —-返回当前系统时区
+(NSTimeZone )systemTimeZone —-返回TimeZone支持时区的键值对
+(instancetype)timeZoneWithAbbreviation:(NSString *)abbreviation —- 通过传入键值对的键,创建对应的时区对象。
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// 大写的MM表示月小写的mm表示分钟
// 大写的SSS表示毫秒小写的ss表示秒
// 大写的HH表示24小时制式的小时小写的hh表示12小时制式的小时 formatter.dateFormat = @"yyyy年MM月dd日 HH:mm:ss.SSS";
// GMT --- Greenwich Mean Time格林尼治标准时间
// +8 --- 东八区
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT+8"];
NSLog(@"%@", [formatter stringFromDate:date]);
NSLog(@"%@", [formatter dateFromString:@"2008年08月08日 00:00:0 0.000"]);
- NULL
表示基础类型指针为空
int *p = NULL;
nil:表示对象指针为空。
id obj = nil;
Nil :表示Class变量为空。
Class class = Nil;
NSNull: 用在数组字典等数据结构中占位,作为空元素。
[NSNull null]; // 创建表示空的对象
- NSDateFormatter
NSDate *now = [NSDate date];
// NSDate对象的timeIntervalSinceDate:可以计算出两个日期之间相差多少秒
int days = (int)lround([now timeIntervalSinceDate:_lendDate] / SECONDS_PER_DAY);
static NSDateFormatter *formatter = nil;
if (!formatter) {
formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone systemTimeZone];
}
[formatter stringFromDate:_lendDate];```
- NSRange
-(NSArray *) findBooksByName:(NSString *) name{
NSMutableArray *tempArray = [NSMutableArray array];
for (CDBook *tempBook in booksArray) {
// NSRange range = [temp.name rangeOfString:name];
// if(range.location != NSNotFound) {
//rangOfString:在一个字符串中查找是否含有另一个字符串
if([tempBook.name rangeOfString:name].location != NSNotFound){
[tempArray addObject:tempBook];
}
}
return [tempArray copy];
}```
- 数据持久化
将对数据结构转换为NSData类对象的过程称为归档(数据的序列化);相反的过程称之为解归档(数据的反序列化)。
#if 1
NSString *str = @"我爱你们";
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
[data writeToFile:@"/Users/Hao/Desktop/b.txt" atomically:NO];
#else
NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Des ktop/b.txt"];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
#endif
}
#if 0
NSArray *array = @[@"apple", @"桔子", @"banana"];
// 创建数据中转站
NSMutableData *mData = [NSMutableData data];
// 创建归档器
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
// 用键值对的方式进行归档(编码)
[arch encodeObject:array forKey:@"abc"];
// 结束归档编码
[arch finishEncoding];
// 将数据写到硬盘文件上
[mData writeToFile:@"/Users/Hao/Desktop/foo" atomically:NO];
#else
// 创建一个数据中转站将文件内容读入中转站
NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Desktop/foo"];
// 创建一个解归档器
NSKeyedUnarchiver *unarch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
// 通过键取出刚才存入的数据(解码)
NSArray *array = [unarch decodeObjectForKey:@"abc"];
for (NSString *str in array) {
NSLog(@"%@", str);
}
#endif
任意对象的序列化和反序列化
@interface CDStudent : NSObject <NSCoding>
-(id) initWithCoder:(NSCoder *)aDecoder {
if(self = [super init]) {
if(aDecoder) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntForKey:@"age"];
} }
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInt:self.age forKey:@"age"];
}
#if 1
CDStudent *stu = [[CDStudent alloc] init];
stu.name = @"张三";
stu.age = 35;
NSMutableData *mData = [NSMutableData data];
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritin gWithMutableData:mData];
[arch encodeObject:stu forKey:@"student"];
[arch finishEncoding];
[mData writeToFile:@"/Users/Hao/Desktop/bar" atomically:NO];
#else
NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Des ktop/bar"];
NSKeyedUnarchiver *unarch = [[NSKeyedUnarchiver alloc] initFor ReadingWithData:data];
CDStudent *stu = [unarch decodeObjectForKey:@"student"];
NSLog(@"%@", stu);
#endif
<u>如果对象中关联了其他对象,如果在归档时要对关联的对象进行归档
那么关联的对象也必须遵循NSCoding协议才能进行归档
否则程序会崩溃</u>
plist文件
[mData writeToFile:FILENAME atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:FILENAME]) {
NSData *data = [NSData dataWithContentsOfFile:FILENAME];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
booksArray = [unarchiver decodeObjectForKey:@"books"];
}
// 获得默认的文件管理器对象
NSFileManager *manager = [NSFileManager defaultManager];
// 创建文件夹
// 如果第二个参数是YES则会在上级文件夹不存在时依次创建出上级文件夹再创建当前指定的文件夹
NSLog(@"%@", [manager createDirectoryAtPath:@"/Users/Hao/Desktop/abc/def/小狗屎" withIntermediateDirectories:YES attributes:nil error:nil]? @"创建文件夹成功": @"创建文件夹失败");
- 协议的作用和语法:协议是一组方法的集合,协议中只有方法的声明没有方法的实现,这些方法是留给该协议的类做出多态实现的方法。协议表示约定、能力、角色。
id<Flyable> bird = [[Bird alloc] init];
id<Flyable> superman = [[Superman alloc] init];
id<Flyable> airplane = [[Airplane alloc] init];
NSArray *array = @[bird, superman, airplane];
for (id<Flyable> temp in array) {
[temp fly];
} ```
// 多态: 同样的指针调用相同的方法做了不同的事情
// 不同的类遵循相同的协议并对协议中的方法给出不同的实现版本
for (id<CDFlyable> temp in array) {
// 在运行时判定指针指向的对象是否遵循协议
if ([temp conformsToProtocol:@protocol(CDFlyable)]) {
[temp fly];
}
}```
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:[NSDate date]];
//return [self initWithHour:comps.hour minute:comps.minute second:comps.second];
if (_delegate && [_delegate conformsToProtocol:@protocol(CDPowerProviderProtocol)]) {
[_delegate providePower];
NSLog(@"电机启动可以刮胡子了...");
}```
- 代理模式:代理对象代理被代理对象的行为,代理对象可以通过被代理对象的指针执行被代理对象的行为,与此同时代理对象可以对这些行为进行
委托回调:回调是一种常用的编程模式,它通常通过设置委托来实现。委托方做不了的事情让被委托方做,被委托方必须遵循某种协议,委托方要持有一个指向该对象的指针。
/*枪手/
@interface Gunman : NSObject <CandidateProtocol>
@property (nonatomic, copy) NSString *name;
// 代理对象中要有一个指向被代理对象的指针
// 通过这个指针代理对象可以调用被代理对象的方法
@property (nonatomic, weak) id<CandidateProtocol> target; ```
-(instancetype)initWithName:(NSString *)name target:(id<CDCandidate>)target {
if (self = [super init]) {
_name = name;
_target = target;
}
return self;
}
-(void) doExam {
// 执行被代理对象的行为
[_target doExam];
// 增强实现
NSLog(@"奋笔疾书正确答案");
NSLog(@"交卷");
}
// 总结: 委托回调的编程模式可以帮助程序实现解耦合
委托方定义一个指针(id<CDCandidate>delegate)指向被委托方,在被委托方中绑定委托,遵循协议即可。
// 定义一个指针指向被委托方
// 当遇到知道什么时候做某事但不知道怎么做的场景
// 都可以使用委托回调的编程模式来实现代码的解耦合
// 创建一个闹钟对象
AlarmClock *ac = [[AlarmClock alloc] init];
// 告诉闹钟待会你要唤醒的对象是谁
// 委托方是闹钟被委托方是人
// 人被唤醒这件事情要委托给人来执行
// 因为人遵循Awakable协议实现了beAwaken方法
ac.delegate = self;
// 调用闹钟的方法设定多少秒之后响闹钟
[ac alarmAfter:seconds];
NSDate *date = [NSDate date];
// 创建一个日历对象
NSCalendar *cal = [NSCalendar currentCalendar];
// 创建一个日期成员对象
NSUInteger flag = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponents *comp = [cal components:flag fromDate:date];
self.hour = (int)[comp hour];
self.minute = (int)[comp minute];
self.second = (int)[comp second];
/**闹钟继承了Clock除了走字和显示时间还要提供定时闹铃的功能*/ ```
@interface AlarmClock : Clock
// 通过delegate属性设置被委托方
// 被委托的对象是一个遵循Awakable协议的对象
// 所以delegate属性的类型是一个指向Awakable对象的指针
@property (nonatomic, weak) id<Awakable> delegate;
/*在指定时间之后响闹钟/
-(void) alarmAfter:(int) seconds;
// 通过指向被委托方的指针调用被委托方的回调方法人被唤醒
// 将self作为参数传入beAwaken方法这样人可以通过时钟对象
// 获得现在时钟上显示的时间实现了数据的反向传递
[self.delegate beAwaken:self]; ```
@interface CDUtility : NSObject
+(void) saveData:(NSData *) data withDataHandler:(id<CDStroageProtocol>) handler;
@end
+(void) saveData:(NSData *)data withDataHandler:(id<CDStroageProtocol>)handler {
if (handler && [handler conformsToProtocol:@protocol(CDStroageProtocol)]) {
[handler store:data];
}
}
NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Desktop/girl.json"];
[CDUtility saveData:data withDataHandler:[[CDRemovableStorage alloc] init]];
- JSON解析
NSData *data = [NSData dataWithContentsOfFile:@"/Users/alvin/Desktop/girl.json"];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
NSArray *items = dict[@"items"];
[items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *str = obj[@"wpic_large"];
// printf("第%ld条: %s\n", idx + 1, str.UTF8String);
NSData *pic = [NSData dataWithContentsOfURL:[NSURL URLWithString:str]];
// NSLog(@"%@", [manager createFileAtPath:@"/Users/chengduqianfeng/Desktop/abc" contents:pic attributes:nil]? @"创建成功":@"创建失败"); NSLog(@"%@",[pic writeToFile:@"/Users/alvin/Desktop/abc" atomically:YES]?@"创建成功":@"创建失败");
}];```
NSURL *url = [NSURL URLWithString:@"http://223.6.252.214/we
ibofun/weibo_list.php?apiver=10500&category=weibo_jokes&page=0&page
_size=30&max_timestamp=-1"];
// 通过该URL以同步方式获取数据
NSData *data = [NSData dataWithContentsOfURL:url];
// 将收到的JSON格式的数据处理成字典对象
NSDictionary *dict = [NSJSONSerialization JSONObjectWithDat
a:data options:0 error:nil];
// 取出字典中的items键对应的数组
NSArray *array = dict[@"items"]; ```
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
[dictionary setValue:@"xiaominfc" forKey:@"username"];
[dictionary setValue:@"1991-03-26" forKey:@"birthday"];
[dictionary setValue:[NSNumber numberWithInteger:23] forKey:@"age"];
NSArray *arrayOfAnthonysChildren = [[NSArray alloc]initWithObjects:@"Java",@"Objective-C",@"Python",@"C++", nil];
[dictionary setValue:arrayOfAnthonysChildren forKey:@"program_language"];
if([NSJSONSerialization isValidJSONObject:dictionary]){
NSLog(@"it is a JSONObject!");
}
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
if([jsonData length] > 0 && error == nil) {
NSString *jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"data:%@",jsonString);
}```
-(void) setValue:(id)value forKey:(NSString *)key {
// 对于属性和JSON数据类型不匹配的情况需要手动转换
if ([key isEqualToString:@"wid"]) {
self.wid = [value integerValue];
}
else if ([key isEqualToString:@"comments"]) {
self.comments = [value integerValue];
}
else if ([key isEqualToString:@"likes"]) {
self.likes = [value doubleValue];
}
else if ([key isEqualToString:@"updateTime"]) {
self.updateTime = [NSDate dateWithTimeIntervalSince1970:[value integerValue]];//将读取的json中的格林威治时间字符串转换为标准时间。
}
else {
// 对于不需要类型转换的键值对组合直接使用KVC赋值
[super setValue:value forKey:key];
// 不能写下面的代码否则会因为递归调用不收敛导致栈溢出
// [self setValue:value forKey:key];
}
}```
// 提示: 使用KVC大招时一定重写此方法
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// 在使用KVC时通常都需要重写此方法来处理不能识别的key
// 如果JSON数据中的键和类的属性名不匹配可以通过下面的字典进行转换
NSDictionary *keyPropDict = @{@"wpic_large": @"largePicUrl", @"update_time": @"updateTime"};
// 如果JSON中的键在类中有与之对应的属性才使用KVC给该属性赋值
// 如果没有对应的属性就什么都不要做
if (keyPropDict[key]) {
[self setValue:value forKey:keyPropDict[key]];
}
}```
static const NSString *PATH = @"/Users/alvin/Desktop";
// 保存图片以及图片描述
void foo(NSArray * array) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *path = [PATH stringByAppendingPathComponent:@"美女图片"];
if (![fileManager fileExistsAtPath:path]) {
[fileManager createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:nil];
}
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CDGirlPhoto *girl = obj;
NSLog(@"%@", girl.updateTime);
NSString *urlStr = girl.largePicUrl;
NSString *filename = [[PATH stringByAppendingPathComponent:@"美女图片"] stringByAppendingPathComponent:[urlStr lastPathComponent]];
[[NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]] writeToFile:filename atomically:YES];
NSString *txtFilename = [[filename substringToIndex:[filename rangeOfString:@"." options:NSBackwardsSearch].location + 1] stringByAppendingString:@"txt"];
[girl.wbody writeToFile:txtFilename atomically:YES encoding:NSUTF8StringEncoding error:nil];
}];
}```
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSData *data = [NSData dataWithContentsOfFile:[PATH stringByAppendingPathComponent:@"girl.json"]];
// 将JSON格式的数据转换成字典
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:nil];
// 通过索引器语法取出items键对应的数组
NSArray *array = dict[@"items"];
NSMutableArray *girls = [NSMutableArray array];
for (NSDictionary *objDict in array) {
// 有一个字典就创建一个与之对应的模型对象
CDGirlPhoto *girl = [[CDGirlPhoto alloc] init];
// 通过KVC(Key Value Coding)方式给对象的属性赋值
[girl setValuesForKeysWithDictionary:objDict];
// 将模型对象添加到数组中保存和管理起来
[girls addObject:girl];
}
foo(girls);
}
return 0;
}```
- 解析XML数据文件
- SAX --- 顺序解析 事件驱动(遇到标签、属性、内容都会引发相应的事件执行事件回调来处理XML文件中的数据)
- DOM (Document Object Model) --- 支持XPath查找,可以动态的增加删除修改节点,占用内存较多
NSURL *url = [NSURL URLWithString:@"http://www.oschina.net/action/api/news_detail?id=44393"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 使用NSData对象创建XML文档对象
// 文档对象是将XML在内存中组织成一棵树
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
// 使用XPath语法从文档对象模型中查找指定节点
NSArray *array = [doc nodesForXPath:@"//relative" error:nil
// 循环取出节点并对节点下的子节点进行进一步解析
for (GDataXMLNode *node in array) {
// 取出子节点的字符换值
NSString *title = [[node nodesForXPath:@"rtitle" error:nil][0] stringValue];
NSString *url = [[node nodesForXPath:@"rurl" error:nil][0] stringValue];
printf("标题%s\n链接地址%s\n\n", title.UTF8String, url .UTF8String);
} ```
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.oschina.net/action/api/news_detail?id=44393"]];
// 根据获得的XML数据创建文档对象(DOM)
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
NSArray *array = [doc nodesForXPath:@"//title" error:nil];
NSLog(@"%@", [[array firstObject] stringValue]);
array = [doc nodesForXPath:@"//relative" error:nil];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
GDataXMLNode *node = obj;
NSLog(@"标题: %@", [[node.children firstObject] stringValue]);
NSLog(@"链接: %@", [[node.children lastObject] stringValue]);
}];```
- **block**
As a property:
`@property (nonatomic,copy) returnType (^blockName)(parameterTypes);`
As a method parameter:
`-(void)someMethodThatTakesABlock:(returnType (^(parameterTypes))blockName;`
+(void)saveData:(NSData *)data withDataHandler:(void (^)(NSData *))dataHandler {
dataHandler(data); } ```
As an argument to a method call:
[someObject someMethodThatTakesABlock:^retuenType (parameters){…}];
[CDMyUtil saveData:data withDataHandler:^(NSData * myData) {
[myData writeToFile:@"" atomically:NO];
}];```
As a typedef:
`typedef returnType (^TypeName)(parameterTypes);`
typedef void (^CDDataHandlerBlockType)(NSData *);
TypeName blockName =^returnType(parameters){…};```
// 声明Block变量
int (^sum)(int, int);
// 定义一个Block并赋值给变量
sum sum=^int(int a,int b){return a+b;};
// 调用Block
printf("%d\n", sum(1, 2));
+(int (^)(int, int)) foo {
int a=1;
// 在Block中变量a是只读的
// 如果想修改它需要用__block修饰
return ^ int (int b, int c) {
return a+b+c; };
} ```