对文件的操作:
#define PATH @"/Users/mac/Desktop/未命名文件夹" #define ERROR(a) if(a){NSLog(@"%@",a);} #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { /* @autoreleasepool { //创建一个单例对象 NSFileManager * fileManage = [NSFileManager defaultManager]; NSError * error = nil; //注意传的是指针的地址,是个** 类型的数据 //这里是浅度遍历只把路径下的文件夹的名字 NSArray * arrary = [fileManage contentsOfDirectoryAtPath:PATH error:&error]; if (error) { //这里文件操作为什么一定要要报错呢? NSLog(@"浅度遍历扑获错误%@",error); exit(-1); } NSLog(@"浅度遍%@",arrary); //这里是深度遍历只把路径下的文件夹以及子文件夹下的所有子文件夹的名字 arrary = [fileManage subpathsOfDirectoryAtPath:PATH error:&error]; if (error) { NSLog(@"深度遍历%@",error); exit(-1); } NSLog(@"深度遍历%@",arrary); //创建目录 //方法的第一个参数:拼接要创建的目录的路径 //第二个参数:表示是否创建中间目录。YES 就是补全中间目录的意思。如果是 YES 那么第一个参数中如果没有中间路径就会报错,有就不会报错,如果是 NO 那么没有中间路径就会报错,没有就不会报错 //第三个参数:可以为空 [fileManage createDirectoryAtPath:[NSString stringWithFormat:@"%@/middle/dir",PATH] withIntermediateDirectories:YES attributes:nil error:&error]; if (error) { NSLog(@"创建目录_>错误捕获%@",error); exit(-1); } //创建一个文件夹 //首先还是要获取一个文件路径 //第一个参数:就是创建的文件夹所在的目标路径 第二个参数:文件的内容,我们也可以在创建的时候不写入内容,之后再写入内容。是一个NAData类型的数据,我们把字符串转化为NSData类型这里用到的方法是[字符串 NSTF8StringEncoding] 第三个参数:文件夹的属性,这里为nil就是使用默认的属性 [fileManage createFileAtPath:[NSString stringWithFormat:@"%@/middle/dir/file",PATH] contents:[@"I am an chinese" dataUsingEncoding:NSUTF8StringEncoding]attributes:nil]; } */ //文件的删除操作 @autoreleasepool { NSFileManager * filemanage = [NSFileManager defaultManager]; NSError * error = nil; //第一个参数:不管是目录还是文件都可以进行删除 [filemanage removeItemAtPath:[NSString stringWithFormat:@"%@/middle",PATH] error:&error]; ERROR(error); NSArray * arrPaht = [filemanage contentsOfDirectoryAtPath:PATH error:nil]; ERROR(error); NSLog(@"文件删除后的遍历操作%@",arrPaht); //文件的移动、拷贝 就是把对应的方法名字removeItemAtPath: 的remove 改为 move 、dele 、copy //文件的拷贝 [filemanage copyItemAtPath:[NSString stringWithFormat:@"%@/NSFlieManage",PATH] toPath:[NSString stringWithFormat:@"%@/NSFlieManage2",PATH] error:&error]; NSArray * arrPaht2 = [filemanage contentsOfDirectoryAtPath:PATH error:nil]; NSLog(@"拷贝后的文件%@",arrPaht2); //将目标1的文件移动到目标2的文件夹下,保持名字不变的操作 [filemanage moveItemAtPath:[NSString stringWithFormat:@"%@/NSFlieManage2",PATH] toPath:[NSString stringWithFormat:@"%@/NSFlieManage/NSFlieManage2",PATH] error:&error]; NSArray * arrPaht3 = [filemanage contentsOfDirectoryAtPath:PATH error:nil]; NSLog(@"移动后的文件%@",arrPaht3); } return 0; }
对文件内容的操作:
文件操作 NSHandle 类文件句柄 打开一个句柄,这个句柄就是这个文件的代表。 对文件的读和写,从文件句柄中读,就是从文件中读,从文件句柄中写,就是从文件中写。 对于读和写都是对于CPU来说的,对于CPU来讲内存就是内部存储器,硬盘就是外部存储器,从硬盘到内存到CPU叫做读,从内存到硬盘叫叫做写。内部存储器(内存)相当于大脑,外部存储器(硬盘)相当于书本。 创建一个文件句柄,文件句柄是靠打开文件来创建的。下面是以制度方式创建的文件句柄 NSfileHandle * hf = [NSFleHanndle fileHandleForReadingAtPath:要打开文件的路径]; 读指定的字节以二进制的形式读(NSData类型的数据) NSData * data = [hf readDataOfLength:3]; //d读指针的偏移,每次读的都会接着上一次读的进行偏移,就像人用手指指着文字进行读书一样 data = [fh readDataOFLength:5];//这里会接着上一次的进度继续的读取数据 NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@“%@”,str); 如果文件的内容不是很多,我们可以直接读取到文件的结尾,使用的方法是: NSData * data2 = [fh readDataToEdndfFile];//直接读取到文件的结尾,这里还是从指针位置为0开始读取,一直到最后 文件的写入: 以只写的方式打开文件句柄 NSFileHandle * fh = [NSFileHandle fileHandleForWritingAtPAth:要写入文件的地址]; [fh writeData:[要写入的内容 dataUsingEncoding:NSUTF8StrinngEncoding]]; 下面的方法是,将文件的内容截止到几个字节,然后再写入内容 [fh truncateFileAtoffset:5];//将原来的文件保留前5个字节 [fh writeData:[要写入的文件内容 dataUsingEncoding:NSUTF8StringEncoding]]; 将文件内容写到原文件的后面,就是追加到原来文件内容的后面 的方法: [fh seekToEndOfFil];//将读写指针设在文件的末端 [fh writeData[要写入的文件的内容 dataUsingEncodinng:NSTF8StringEncoding]];
通知中心 Notificaton:
通知中心 NSNotification
什么是通知中心:
通知中心就是广播设计模式,是一种设计模式。我们在项目中多个对象之间需要通信,就可以使用通知中心。也可以说通知中心是单例
使用场景:
一般用于以下两个场景:
(1)页面关联不大,但是需要传递信息的地方。让一个页面作为发送者,另一个页面作为监听者
(2)需要向多个地方发送消息。一个页面作为发送者,多个页面作为监听者。
在实际的开发中,单例,代理,通知中心是用的非常的多,要掌握好
如何创建一个通知中心:
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
通知中心要使用到的方法:发送通知、接受通知
通知的原理:
信息的发送者要吧信息发送给监听者,监听者收到信息后就做出相应的回应。
如何使用通知:
首先我们要创建一个通知对象,然后使用通知类NSNotification的 postNotificationName: object: userInfo:方法去发送一个通知。然后 用 addObserver: selector: name: object:方法去接受消息。
如何发送消息:
[通知中心对象 postNotificationName:@"BJBroadcoast" object:self userInfo:dict];{参数讲解:第一个参数:广播的频段 第二个参数:广播的对象 第三个参数:广播的内容(需要定义一个字典)}
如何接收消息:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recvBcast:) name:@"BJBroadcoast" object:nil];
//这里 name 的属性值要与前面的 通知中心的第三个参数通知内容(字典中的数据一致)
-(void)recvBcast:(NSNotification *)notify{/接收消息的方法实现,这里要注意接受数据的时候是 NSNotification类对象来接受的,不是NSNotificationCenter 来接收的
//notify 就是具体的广播消息
NSLog(@"notify is %@",notify.name);
}
对应的例子代码:
#import <Foundation/Foundation.h> #import "Listener.h" #import "BJBroadcast.h" int main(int argc, const char * argv[]) { //BJBrocast 北京广播电台 //Listener 听众 @autoreleasepool { //观众先去监听,才能够接受到广播。如果观众后接听,那就让广播不停的去发送信息 Listener * listen = [[Listener alloc]init]; [listen wantToListern]; BJBroadcast * bj = [[BJBroadcast alloc]init]; [bj broadcast]; //不停的发送广播 [bj broadcastLooper]; Listener * li = [[Listener alloc]init]; [li wantToListern]; //防止计数器退出 [[NSRunLoop currentRunLoop] run]; } return 0; }
#import <Foundation/Foundation.h> @interface BJBroadcast : NSObject -(void)broadcastLooper; -(void)broadcast; @end ----------------------------------------------------------------------------------------------------------------(BJBroadcast.m文件) #import "BJBroadcast.h" @implementation BJBroadcast -(void)broadcastLooper{ //启动一个定时器定时的发送广播 [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(broadcast) userInfo:nil repeats:YES]; } -(void)broadcast{ //1. 取得通知中心 // NSNotificationCenter 在UI里有个致命的缺陷,就是子线程和重线程之间的冲突 NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; static int i ; NSString * count = [NSString stringWithFormat:@"bcast %d",i++]; //消息内容 NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:@"BJbrocast",@"name" ,count,@"Value",nil]; //2. 发送广播 //第一个参数:广播的频段 第二个参数:广播的对象 第三个参数:广播的内容 [nc postNotificationName:@"BJBroadcoast" object:self userInfo:dict]; } @end
————————————————————————————————————————————————————————(.h文件) #import <Foundation/Foundation.h> @interface Listener : NSObject //想听广播 -(void)wantToListern; @end ————————————————————————————————————————————————————————(.m文件) #import "Listener.h" @implementation Listener //想听广播 -(void)wantToListern{ //1.要注册 //param1 ,param2 这两个参数是只要有BJBroadcoast 广播就调用 [self recvBcast:]方法。 //这里 name 的属性值要与前面的 通知中心的第三个参数通知内容(字典中的数据一致) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recvBcast:) name:@"BJBroadcoast" object:nil]; //2.要真正的接受广播数据 } -(void)recvBcast:(NSNotification *)notify{ //notify 就是具体的广播消息 NSLog(@"notify is %@",notify.name); } @end
通知在UI中对于子线程和重线程的解决方案:
当用NSNotification,在回调函数里面对tableview进行reloadData时,并不能更新UI,而且还会导致以后都更新不了。后来查了一些资料才发现,postNotification之后调用回调函数,相当于开了一个子线程,而子线程中是不能更新UI的。所以要想在notification的回调里面更新UI,必须用
dispatch_async(dispath_get_main_queue(),^{
[tableview reloadData];
}];
(总结)代码中的全局变量的使用, 定时器循环调用一个方法,通知中心的单例对象的创建
NSNotification 里面有三个参数,点开查看:
@interface NSNotification : NSObject <NSCopying, NSCoding>
@property (readonly, copy) NSString *name;
@property (readonly, retain) id object;
@property (readonly, copy) NSDictionary *userInfo;
上面的三个参数于我们 消息中心 NSNotificationCenter 的消息发送对象里面的三个参数对应,这就是为啥监听者类在接受消息的时候,要进行注册的缘故。