解析文件和多线程 线程同步

来源:互联网 发布:中国十大网络神兽动图 编辑:程序博客网 时间:2024/06/05 14:56
XML解析需要添加一个libxml2.dylib的Frameworks文件
然后要引入GDataXMLNode.h和.m文件 
(JSON不用引入Frameworks但也许引入JSONKit.h和.m文件)
同步和异步的主要区别就是运行的时候是否会创建一个新的线程,异步的会创建一个新的,而同步的并不会。在一些应用程序中应该避免同步请求很大的文件。可以开辟一个新的线程达到异步的效果。[NSThread detachNewThreadSelector:];
异步联接发送请求 就是用到NSURLConnectionDelegate和NSURLConnectionDataDelegate这两个代理方法中的四个方法 
get方式用的是NSURLRequest post方式用的是NSURLMutableRequest 并添加这两个改变request.HTTPMethod = @"POST";request.HTTPBody = requestData; 发送链接都是一样的[NSURLConnection connectionWithRequest:request delegate:self];


系统自带的解析

NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:receiveData options:NSJSONReadingAllowFragments error:nil];


JSON解析 get连接 (JSON解析除了有JSONKit外还有SBJSON(即 json-framework) TouchJSON JSON的数据可读性不如XML)

josn里文件的对应关系:
Number -> NSNumber String -> NSString Array -> NSArray Object -> NSDictionary 另外:null -> NNSNull true and false -> NNSNumber

NSStringEncoding encode = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);//可以转码的工具这个是非UTF8的

NSString *urlString = [[NSString allocinitWithFormat:@"http://api.tudou.com/v3/gw?method=item.ranking&appKey=myKey&format=json&pageNo=1&pageSize=20&channelId=22&inDays=30&sort=m"];

NSURLRequest *request = [[NSURLRequest allocinitWithURL: [NSURL URLWithString:urlString]];

NSString *jsonString = [[NSString allocinitWithData:receiveData encoding:NSUTF8StringEncoding];

[jsonString objectFromJSONString];       或者  NSDictionary *data = [json objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];

[jsonDicOutside valueForKey:@"multiPageResult"];


XML解析 post连接

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://tm.mbpay.cn:8082"]];

request.HTTPMethod = @"POST";

request.HTTPBody = requestData;(NSData *requestData = [NSData dataWithContentsOfFile:[[NSBundle mainBundlepathForResource:@"request" ofType:@"xml"]];post携带的数据一般由服务器人提供)

[NSURLConnection connectionWithRequest:request delegate:self];


GDataXMLDocument *xmlDocument = [[GDataXMLDocument allocinitWithData:self.receiveData options:0 error:NULL];

NSArray *nodes = [xmlDocument nodesForXPath:@"//body//rows//wp_film" error:NULL];//可以打印一下xmlDocument看内容再取节点

for (GDataXMLDocument *node in nodes) //遍历数组方便下面引用

myMovie.movieID = [[node attributeForName:@"id"stringValue];//具体用数据了







多线程加载
进程是一个具体的应用程序 线程是进程中的一个分支,为单独完成程序某项功能而存在 应用程序可以有一个或多个进程,一个进程可以有一个或多个线程,且有一个是主线程其它为子线程 单线程任务是顺序执行,多线程是并行,在非主线程进行信息加载 主线程进行UI操作
线程同步:多线程同时操作一个数据 对数据添加保护 这个保护就是线程同步
线程异步:多个线程互不影响分别操作自己的数据
并发:多个线程同时运行
线程间通信:一个线程执行之后另一个线程开始执行
线程开销:线程切换之间的资源耗费(时间和空间)
线程互斥:多个线程访问同一个数据的时候的 只允许一个线程修改 执行互斥操纵以前先检查NSLock 打开状态则可继续运行并设置为关闭状态

线程下载完图片后怎么通知主线程更新界面呢?

[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

NSThread:

     代表执行的线程,可以使用该类的对象封装线程操作。

[NSTread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];//系统

[NSThread *_thread =[[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];//类自己开辟线程 自己管理

[_thread start];

     NSOperation

      定义了任务的执行环境、状态等基本属性,继续该类来指定具体的操作,通常情况下,编写NSOperation的子类来定义具体的操作。该类为抽象类,NSOperation的子类NSInvocationOperation(可能要用到NSInvocation签名)NSBlockOperation) 可以指定操作方法。

NSInvocationOperation *op=[[NSInvocationOperation alloc] initWithTarget:self  selector:@selector(task)  object:nil];

[op  start];

      NSOperationQueue

       运行队列(Operation queue)的管理者,配合NSOperation的子类对象和NSIvocationOperation对象使用,通过添加操作对象完成并发操作。将Operation对象放入NSOperationQueue里,系统会自动生成一个线程来执行Operation 如果将最大的并发数设置为1的话则同时只有一个线程运行,由此解决线程同步问题

NSOperationQueue *queue=[[NSOperation alloc]  init]    

[queue  setMaxConcurrentOperationCount:1];//指定能够同时并发执行的操作个数 [queue addOperation:op];

      NSRunLoop:

      表示程序的运行回路,该类的对象可以接收到各种时间(如来自NSTimer的时间变化),协助程序对这些事件做出响应。

  GCD

     NSOperationQueue *queue = [[NSOperation alloc]init];
     [queue setMaxConcurrentOperationCount:1];

方法1: 同步加载图片(很慢)

[self loadImageForMovie:movie];

方法1.1: NSInvocation同步加载图片

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(loadAndRefreshForMovie:)]];

//根据方法签名创建一个NSInvocation invocation.target = self; invocation.selector = @selector(loadAndRefreshForMovie:);

[invocation setArgument:&movie atIndex:2];//retain 所有参数,防止参数被释放dealloc argument 为参数的指针

index 为参数的位置(注意:由2开始)原因为:0 1 两个参数已经被target selector占用

//消息调用

[invocation invoke];


方法2: NSThread(手动开始)

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadAndRefreshForMovie:) object:movie];

[thread start];

[thread release];

方法3: NSThread简便写法

[NSThread detachNewThreadSelector:@selector(loadAndRefreshForMovie:) toTarget:self withObject:movie];

方法4: 使用NSInvocationOperationNSOperationQueue来做多线程加载图片

 // 创建invocation对象

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(loadAndRefreshForMovie:)]];

invocation.target = self;

invocation.selector = @selector(loadAndRefreshForMovie:);

[invocation setArgument:&movie atIndex:2];

// invocation对象封装为NSInvocationOperation

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];

// operation对象加到operation queue

[self.operationQueue addOperation:operation];

[operation release];

方法5: GCD-GrandCentralDispath来执行后台加载和刷新

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

[self loadImageForMovie:movie];dispatch_async(dispatch_get_main_queue(), ^{

[self refreshTableViewCellForMovie:movie];});

});

方法6不显式创建线程的方法:用NSObject的类方法  performSelectorInBackground:withObject: 创建一个线程当多个线程同时运行时,就会出现访问资源的同步问题.

[self performSelectorInBackground:@selector(loadAndRefreshForMovie:) withObject:movie];

方法7: addOperationWithBlock 添加一个块到线程队列

[self.operationQueue addOperationWithBlock:^{

[self loadAndRefreshForMovie:movie];

}];







线程同步

我们演示一个经典的卖票的例子来讲NSThread的线程同步:

[cpp] view plaincopy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @class ViewController;  
  4.   
  5. @interface AppDelegate : UIResponder <UIApplicationDelegate>  
  6. {  
  7.     int tickets;  
  8.     int count;  
  9.     NSThread* ticketsThreadone;  
  10.     NSThread* ticketsThreadtwo;  
  11.     NSCondition* ticketsCondition;  
  12.     NSLock *theLock;  
  13. }  
  14. @property (strong, nonatomic) UIWindow *window;  
  15.   
  16. @property (strong, nonatomic) ViewController *viewController;  
  17.   
  18. @end  

[cpp] view plaincopy
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  2. {  
  3.       
  4.     tickets = 100;  
  5.     count = 0;  
  6.     theLock = [[NSLock alloc] init];  
  7.     // 锁对象  
  8.     ticketsCondition = [[NSCondition alloc] init];  
  9.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  10.     [ticketsThreadone setName:@"Thread-1"];  
  11.     [ticketsThreadone start];  
  12.       
  13.       
  14.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  15.     [ticketsThreadtwo setName:@"Thread-2"];  
  16.     [ticketsThreadtwo start];  
  17.       
  18.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  19.     // Override point for customization after application launch.  
  20.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
  21.     self.window.rootViewController = self.viewController;  
  22.     [self.window makeKeyAndVisible];  
  23.     return YES;  
  24. }  
  25.   
  26. - (void)run{  
  27.     while (TRUE) {  
  28.         // 上锁  
  29. //        [ticketsCondition lock];  
  30.         [theLock lock];  
  31.         if(tickets >= 0){  
  32.             [NSThread sleepForTimeInterval:0.09];  
  33.             count = 100 - tickets;  
  34.             NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  
  35.             tickets--;  
  36.         }else{  
  37.             break;  
  38.         }  
  39.         [theLock unlock];  
  40. //        [ticketsCondition unlock];  
  41.     }  
  42. }  
如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。

线程的顺序执行

他们都可以通过

        [ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

[cpp] view plaincopy
  1. #import "AppDelegate.h"  
  2.   
  3. #import "ViewController.h"  
  4.   
  5. @implementation AppDelegate  
  6.   
  7. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  8. {  
  9.       
  10.     tickets = 100;  
  11.     count = 0;  
  12.     theLock = [[NSLock alloc] init];  
  13.     // 锁对象  
  14.     ticketsCondition = [[NSCondition alloc] init];  
  15.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  16.     [ticketsThreadone setName:@"Thread-1"];  
  17.     [ticketsThreadone start];  
  18.       
  19.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  20.     [ticketsThreadtwo setName:@"Thread-2"];  
  21.     [ticketsThreadtwo start];  
  22.       
  23.     NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];  
  24.     [ticketsThreadthree setName:@"Thread-3"];  
  25.     [ticketsThreadthree start];      
  26.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  27.     // Override point for customization after application launch.  
  28.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
  29.     self.window.rootViewController = self.viewController;  
  30.     [self.window makeKeyAndVisible];  
  31.     return YES;  
  32. }  
  33.   
  34. -(void)run3{  
  35.     while (YES) {  
  36.         [ticketsCondition lock];  
  37.         [NSThread sleepForTimeInterval:3];  
  38.         [ticketsCondition signal];  
  39.         [ticketsCondition unlock];  
  40.     }  
  41. }  
  42.   
  43. - (void)run{  
  44.     while (TRUE) {  
  45.         // 上锁  
  46.         [ticketsCondition lock];  
  47.         [ticketsCondition wait];  
  48.         [theLock lock];  
  49.         if(tickets >= 0){  
  50.             [NSThread sleepForTimeInterval:0.09];  
  51.             count = 100 - tickets;  
  52.             NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  
  53.             tickets--;  
  54.         }else{  
  55.             break;  
  56.         }  
  57.         [theLock unlock];  
  58.         [ticketsCondition unlock];  
  59.     }  
  60. }  
wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait

其他同步

我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
- (void)doSomeThing:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}
还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习


NSCondition的用法

使用NSCondition,实现多线程的同步,即,可实现生产者消费者问题。

基本思路是,首先要创建公用的NSCondition实例。然后:

  • 消费者取得锁,取产品,如果没有,则wait,这时会释放锁,直到有线程唤醒它去消费产品;
  • 生产者制造产品,首先也是要取得锁,然后生产,再发signal,这样可唤醒wait的消费者。
- (IBAction)conditionTest:(id)sender{    NSLog(@"begin condition works!");    products = [[NSMutableArray alloc] init];    condition = [[NSCondition alloc] init];        [NSThread detachNewThreadSelector:@selector(createProducter) toTarget:self withObject:nil];    [NSThread detachNewThreadSelector:@selector(createConsumenr) toTarget:self withObject:nil];}- (void)createConsumenr{    [condition lock];    while ([products count] == 0) {        NSLog(@"wait for products");        [condition wait];    }    [products removeObjectAtIndex:0];    NSLog(@"comsume a product");    [condition unlock];}- (void)createProducter{    [condition lock];    [products addObject:[[NSObject alloc] init]];    NSLog(@"produce a product");    [condition signal];    [condition unlock];}
原创粉丝点击