使用NSOperation为你的app加速

app store中的很多应用程序非常的笨重,他们有好的界面,但操作性很差,比如说当程序从网上或本地载入数据的时候,界面被冻结了,用户只能等程序完全载入数据之后才能进行操作。
当打开一个应用程序时,iphone会产生一个包含main方法的线程,所用程序中的界面都是运行在这个线程之中的(table views, tab bars, alerts…),有时候我们会用数据填充这些view,现在问题是如何有效的载入数据,并且用户还能自如的操作程序。
下面要说方法的并不是要在用户载入数据的时候在界面上提示“loading”的信息,虽然这种方式在有些时候是可以被接受的,但当数据在main线程之外被载入是并不是最有效的方式。
先看一下要演示的程序:
使用NSOperation为你的app加速

这个程序将从网络上下载10,000条数据,并填入到UITableView中,现面的代码将首先演示一种错误的方式:
错误 (源码 )

 

@implementation



 RootViewController

@synthesize



 array



;

 

-



 (



void



)



viewDidLoad {





[



super viewDidLoad]



;

 

/* Adding the button */





self



.navigationItem.rightBarButtonItem =



 [



[



UIBarButtonItem alloc



]



 initWithTitle



:



@"Load"





style



:



UIBarButtonItemStyleDone

target



:



self





action



:



@selector



(



loadData)



]



;

 

/* Initialize our array */





NSMutableArray



 *



_array =



 [



[



NSMutableArray



 alloc



]



 initWithCapacity



:



10000



]



;

self



.array



 =



 _array;

[



_array release



]



;

}





 

// Fires when the user presses the load button





-



 (



void



)



 loadData {





 

/* Grab web data */





NSURL



 *



dataURL =



 [



NSURL



 URLWithString



:



@"http://icodeblog.com/samples/nsoperation/data.plist"



]



;

 

NSArray



 *



tmp_array =



 [



NSArray



 arrayWithContentsOfURL



:



dataURL]



;

 

/* Populate our array with the web data */





for



(



NSString



 *



str in



 tmp_array)



 {





[



self



.array



 addObject



:



str]



;

}





 

/* reload the table */





[



self



.tableView



 reloadData



]



;

}





 

#pragma mark Table view methods





 

-



 (



NSInteger)



numberOfSectionsInTableView:



(



UITableView *



)



tableView



 {





return



 1



;

}





 

-



 (



NSInteger)



tableView



:



(



UITableView *



)



tableView



 numberOfRowsInSection:



(



NSInteger)



section {





return



 [



self



.array



 count



]



;

}





 

-



 (



UITableViewCell *



)



tableView



:



(



UITableView *



)



tableView



 cellForRowAtIndexPath:



(



NSIndexPath



 *



)



indexPath {





 

static



 NSString



 *



CellIdentifier =



 @"Cell"



;

 

UITableViewCell *



cell



 =



 [



tableView



 dequeueReusableCellWithIdentifier:



CellIdentifier]



;

if



 (



cell



 ==



 nil



)



 {





cell



 =



 [



[



[



UITableViewCell alloc



]



 initWithStyle:



UITableViewCellStyleDefault

reuseIdentifier:



CellIdentifier]



 autorelease



]



;

}





 

/* Display the text of the array */





[



cell



.textLabel setText:



[



self



.array



 objectAtIndex



:



indexPath.row



]



]



;

 

return



 cell



;

}





 

-



 (



void



)



dealloc



 {





[



super dealloc



]



;

[



array



 release



]



;

}





 

@end





 


当点击“load”按钮时程序会被冻结,直到将数据完全下载并填入Tableview,在这期间用户不能做任何的事情。
在给出解决方式之前先来看一下NSOperationQueue和NSOperation:

The NSOperation and NSOperationQueue classes  alleviate much of the pain of multi-threading, allowing you to simply  define your tasks, set any dependencies that exist, and fire them off.  Each task, or  operation , is represented by an instance  of an NSOperation class; the NSOperationQueueclass  takes care of starting the operations, ensuring that they are run in  the appropriate order, and accounting for any priorities that have been  set.

下面要做的是建立NSOperationQueue和NSOperations。NSOperationQueue会建立一个线程,每个加入到线程operation会有序的执行。
下面是使用NSOperationQueue的过程:

  1. 建立一个NSOperationQueue的对象
  2. 建立一个NSOperation的对象
  3. 将operation加入到NSOperationQueue中
  4. release掉operation

使用NSOperation有几种,现在介绍最简单的一种NSInvocationOperation,NSInvocationOperation是NSOperation的子类,允许运行在operation中的targer和selector。  下面是执行NSInvocationOperation的一个例子:

 

NSOperationQueue



 *



queue =



 [



NSOperationQueue



 new



]



;

 

NSInvocationOperation



 *



operation



 =



 [



[



NSInvocationOperation



 alloc



]



 initWithTarget



:



self





selector



:



@selector



(



methodToCall)





object



:



objectToPassToMethod]



;

 

[



queue addOperation:



operation



]



;

[



operation



 release



]



;

 

 


下面是我们用正确的方式实现的程序:
正确的方式(下载源码 )

 

@implementation



 RootViewController

@synthesize



 array



;

 

-



 (



void



)



viewDidLoad {





    [



super viewDidLoad]



;

 

    self



.navigationItem.rightBarButtonItem =



 [



[



UIBarButtonItem alloc



]



 initWithTitle



:



@"Load"





       style



:



UIBarButtonItemStyleDone

       target



:



self





       action



:



@selector



(



loadData)



]



;

 

    NSMutableArray



 *



_array =



 [



[



NSMutableArray



 alloc



]



 initWithCapacity



:



10000



]



;

    self



.array



 =



 _array;

    [



_array release



]



;

}





 

-



 (



void



)



 loadData {





 

    /* Operation Queue init (autorelease) */





    NSOperationQueue



 *



queue =



 [



NSOperationQueue



 new



]



;

 

    /* Create our NSInvocationOperation to call loadDataWithOperation, passing in nil */





    NSInvocationOperation



 *



operation



 =



 [



[



NSInvocationOperation



 alloc



]



 initWithTarget



:



self





        selector



:



@selector



(



loadDataWithOperation)





        object



:



nil



]



;

 

    /* Add the operation to the queue */





    [



queue addOperation:



operation



]



;

    [



operation



 release



]



;

}





 

-



 (



void



)



 loadDataWithOperation {





    NSURL



 *



dataURL =



 [



NSURL



 URLWithString



:



@"http://icodeblog.com/samples/nsoperation/data.plist"



]



;

 

    NSArray



 *



tmp_array =



 [



NSArray



 arrayWithContentsOfURL



:



dataURL]



;

 

    for



(



NSString



 *



str in



 tmp_array)



 {





        [



self



.array



 addObject



:



str]



;

    }





 

    [



self



.tableView



 reloadData



]



;

}





 

#pragma mark Table view methods





 

-



 (



NSInteger)



numberOfSectionsInTableView:



(



UITableView *



)



tableView



 {





    return



 1



;

}





 

-



 (



NSInteger)



tableView



:



(



UITableView *



)



tableView



 numberOfRowsInSection:



(



NSInteger)



section {





    return



 [



self



.array



 count



]



;

}





 

-



 (



UITableViewCell *



)



tableView



:



(



UITableView *



)



tableView



 cellForRowAtIndexPath:



(



NSIndexPath



 *



)



indexPath {





 

    static



 NSString



 *



CellIdentifier =



 @"Cell"



;

 

    UITableViewCell *



cell



 =



 [



tableView



 dequeueReusableCellWithIdentifier:



CellIdentifier]



;

    if



 (



cell



 ==



 nil



)



 {





        cell



 =



 [



[



[



UITableViewCell alloc



]



 initWithStyle:



UITableViewCellStyleDefault reuseIdentifier:



CellIdentifier]



 autorelease



]



;

    }





 

    [



cell



.textLabel setText:



[



self



.array



 objectAtIndex



:



indexPath.row



]



]



;

 

    return



 cell



;

}





 

-



 (



void



)



dealloc



 {





    [



super dealloc



]



;

    [



array



 release



]



;

}





 


再次运行程序,当点击“load”按钮时界面是否还被“冻结”呢,程序并没有增加很多的代码,但确大大的提高了用户体验。

你可能感兴趣的:(Opera)