Showing posts with label iOS. Show all posts
Showing posts with label iOS. Show all posts

Monday, February 24, 2014

Introduction to Grand Central Dispatch


GCD is an extremely important feature introduced in iOS 4.0, OS X 10.6 and later versions.
Its used to distribute the computation across multiple cores dispatching any number of threads needed and  it is optimized to work with devices with multi-core processors.

When using GCD you don’t need to handle any multiple threads yourself, GCD technology will take care of that for you, so you can get to focus on the task itself.

GCD works with Blocks, blocks of code that you need to execute in the background,
in low, default or high priority queue, in a serial or concurrent order.

Using GCD in your application will bring a great benefit of all the features mentioned above without the hassle of managing the threads your self and knowing that the GCD technology will be utilizing multi-core processors found in iOS devices today.

Before we dig into GCD itself we’ll need to be comfortable using blocks. Blocks are a C-level syntactic and runtime feature that let you pass a function as an argument, store it, or execute it on multiple threads. Blocks look very similar to functions, instead of the name of the function replace it with ^ and you’re good to go.

To learn more about blocks visit:







You can use a block for example as an argument in a method like :
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
where the block parameter is expecting an object, idx and stop.

Here is one example of how to use a block for enumerating on an array:

NSArray *inputArray = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4",[NSObject new],@"a",@"b", nil];
   
[inputArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
    if (![obj isKindOfClass:[NSString class]]) {
        NSLog(@"found the first different Object: %@",obj);
        *stop = YES;
    }
    else {
        NSLog(@"%@ at index:%d", obj, idx);
    }
    
    return;
}];

So the output will be:
1 at index:0
2 at index:1
3 at index:2
4 at index:3
found the first different Object:

Now that we know more about blocks, I’ll show you how you can add them to a serial queue.
Adding blocks to serial queues ensures that these blocks of code will be executed one after the other. If one block is taking too long, the rest of the blocks will have to wait until its done.
Serial blocks are useful in many cases where ensuring the order of execution is critical.

Lets say we have a block with this definition:
static void (^counterBlock)(int, char, NSUInteger, GCDMaster *) = ^(int count, char letter, NSUInteger blockNumber, GCDMaster *delegate){
       … block does some work here
}
This block is named counterBlock and it takes arguments: int, char, NSUInteger and an object typed GCDMaster.
The arguments in this block are passed in from the method calling the block. As you saw earlier, you can specify any configuration of a block just like you would do with functions.




Now lets talk about Dispatch Queues. Apple’s definition of Dispatch Queues is:
Dispatch queues are a C-based mechanism for executing custom tasks. A dispatch queue executes tasks either serially or concurrently but always in a first-in, first-out order. (In other words, a dispatch queue always dequeues and starts tasks in the same order in which they were added to the queue.) A serial dispatch queue runs only one task at a time, waiting until that task is complete before dequeuing and starting a new one. By contrast, a concurrent dispatch queue starts as many tasks as it can without waiting for already started tasks to finish.


We want to dispatch a few of these blocks on our serial Queue.

Lets start by creating a serial queue:
dispatch_queue_t serialQueue = dispatch_queue_create("com.3Pillar.SerialQueue", NULL);
This will define a serial queue with a reverse domain name so we can identify our queues.

Next we will add 4 of these blocks with different arguments to run serially on the queue:
dispatch_async(serialQueue, ^{counterBlock(20000 ,'a' ,0 ,self);});
dispatch_async(serialQueue, ^{counterBlock(1000  ,'A' ,1 ,self);});
dispatch_async(serialQueue, ^{counterBlock(20000 ,'0' ,2 ,self);});
dispatch_async(serialQueue, ^{counterBlock(2000  ,'Z' ,3 ,self);});

What we did now is we added 4 blocks to our queue “serialQueue” with various different arguments. These blocks will be executed one after the other. When block 1 is finished 2 is started and so forth.
So if we have a log message when the block start and end it will look like this:

==block 1 started ==
==block 1 ended ==
==block 2 started ==
==block 2 ended ==
==block 3 started ==
…           

But if we would want to execute the blocks concurrently and we don’t have the need to run them sequentially then we’ll need to create a concurrent queue.
Apple provides you with a number of concurrent queues that you can access from you’re application. These queues are global and they have 3 priorities DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_PRIORITY_DEFAULT and DISPATCH_QUEUE_PRIORITY_LOW priority.
To get a concurrent queue:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);

Then we add the blocks to the queue the same way as before:
dispatch_async(concurrentQueue, ^{counterBlock(20000 ,'a' ,0 ,self);});
dispatch_async(concurrentQueue, ^{counterBlock(1000  ,'A' ,1 ,self);});
dispatch_async(concurrentQueue, ^{counterBlock(20000 ,'0' ,2 ,self);});
dispatch_async(concurrentQueue, ^{counterBlock(2000  ,'Z' ,3 ,self);});

So GCD runs these blocks concurrently, there is no way to expect which one executes first.
So the output would be random like this:
==block 2 started ==
==block 3 started ==
==block 3 ended ==
==block 1 started ==

So once the Queue is running you can suspend it and resume it by calling the appropriate methods dispatch_suspend and dispatch_resume. Note that the calls to dispatch_suspend and dispatch_resume must be balanced.

Please feel free to run the attached project with the example given in this blog yourself and feel free to experiment with GCD and become familiar with it. Once you start getting comfortable working with blocks and using queues you will be able to introduce many performance improvements to your code and send heavy operations back to a GCD queue while freeing the UI to move freely 

Download project on GitHub
https://github.com/edwardIshaq/GCDDemo

Friday, February 21, 2014

GNUStep

If you wondered how apple implemented their Cocoa Framework then you will enjoy reading the source code of GNUStep.

GNUstep is a compatible implementation with the Cocoa Framework

Ubiquity App - Thermopylae Science + Technology

One of my first iOS projects that I've worked on at Thermopylae Science + Technology.
Which is a platform that allows the admin to construct the application on the server reflecting to all the mobile app users. The web platform enables the admin to add many different types of widgets including but not limited to Youtube videos, Flicker photo streams, Twitter feeds, Track information, Map layers, Map Pins internal routing and so on.

More information:
Ubiquity - By Thermopylae Science + Technology







Thursday, February 13, 2014

Monday, October 21, 2013

UICollectionView tutorial

UICollectionView is one of the new exciting features introduced in iOS 6. It enables you to organize your views on the screen dynamically. You can implement grids, stacks, circular or any other arrangement you like.


Collection View building blocks

UICollectionView is very similar to  UITableView. The UICollectionView has a delegate and dataSource protocols and a UICollectionViewLayout object that provides essential information for the collection's construction and workflow.
1. Class Structure
the dataSource protocol is very similar to the tableView dataSource protocol, it breaks down the structure to sections and items in each section. Although its up to the UICollectionViewLayout object to decide how to present them on the content area. To do so the layout object can choose to extend the UICollectionViewDelegate just like in the case of the flow layout where it extends the UICollectionViewDelegate into a new protocol called UICollectionViewDelegateFlowLayout. If you choose to provide your own layout and you need to customize your delegate then you should also extend the UICollectionViewDelegate to your own needs. The layout's job is as follow: 1. prepare the layout (which we'll dig into at a later point)  2. provide the content size 3. provide layout attributes objects for the cells that are displayed in some rect on the collection view These layout attributes of class UICollectionViewLayoutAttributes provide basic information such as frame, center, alpha, zIndex attributes that are later applied on the cell. Which will result in positioning these cells in the appropriate place in the collection view.

Flow Layout

What is UICollectionFlowLayout ? 

Flow layout object provides a customizable way to organize the cells in the collection view. Layout objects in general are designed to calculate and provide specific attributes to cells and decoration views.
2. FlowLayout's arrangement of the view elements in the collectionView
Courtesy of Apple.com
as you can see from the diagram above, the cells are laid out one after the other and they flow from the left to right.
3. notice the count
 In the screen shot above you can see how each cell displays its section and index above to demonstrate their position in relation to the index. Flow layout can change the scrolling direction to horizontal as well as vertical.

When to use UICollectionViewFlowLayout ?

Flow layout is useful if you want to display your objects in a grid, single file/line anything that has a linear flow to it could be implemented using the flow layout.

Configuring flow layout

Flow layout allows you to configure:
- scrollDirection: horizontal or vertical
- line spacings, which you can see in the example above that a minimum spacing is maintained.
- item size
- header and footer reference sizes
4. header and footers for each section
So, lets start building this collection example step by step.
FlowLayoutExample.h
@interface FlowLayoutExample : UIViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (retain, nonatomic) IBOutlet UICollectionView *collectionView;
@end
Straight forward as you can see, my view controller implements the UICollectionViewDataSource and the UICollectionViewDelegateFlowLayout for the layout and datasource. And we have an outlet for our UICollectionView.
lets configure our collection view
FlowLayoutExample.m
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.collectionView.dataSource = self;//1
    self.collectionView.delegate = self;//1
    //register cell
    [self.collectionView registerClass:[SimpleCell class] forCellWithReuseIdentifier:@"SIMPLE_CELL_ID"];
    //register header
    UINib *headerNib = [UINib nibWithNibName:@"HeaderView" bundle:nil];
    [self.collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HEADER_ID"];
    //register footer
    UINib *footerNib = [UINib nibWithNibName:@"FooterView" bundle:nil];
    [self.collectionView registerNib:footerNib forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FOOTER_ID"];
     //adjust layout
    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;
    layout.minimumLineSpacing = 20.0;
  layout.itemSize = CGSizeMake(100, 100);
    layout.sectionInset = UIEdgeInsetsMake(20, 20, 40, 20);
    layout.headerReferenceSize = CGSizeMake(50, 65);
    layout.footerReferenceSize = CGSizeMake(50, 75);
}
Lets go through this:
1 - set the collectionView's delegate and dataSource to be my viewController's responsibilities. we declared in the header that we'll be implementing these protocols.
2- registering a class for the cell, in this step we tell the UICollectionView which class will be our cell made of and assign it a reuse identifier. UICollectionView will later instantiate cells of that class when we need them.
3- register header, just to demonstrate the different ways I registered the header using a Nib and not a class. UICollectionView allows you either. You notice that we registered this header for: SupplementaryViewOfKind:UICollectionElementKindSectionHeader. UICollectionView enables you to display some meta data on your cells and FlowLayout specifically comes equipped with header and footer. As you build your own layouts you can define more supplementary views of your own.
4- register footer, same as the header.
5- adjust layout. here we tweak our layout object
    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;
Since we never assigned the layout object our selfs, it was assigned for us in the interface builder:
5. layout config in Xib
Layout: Flow layout
Scroll Direction: Vertical
Also you could setup the Header & Footer from Xib to some degree here.
you can see that we configured the layout such that it keeps a minimum 20 px between the lines. We set each item to be of size 100x100, which later you can change on a per item basis in a method called: collectionView:layout:sizeForItemAtIndexPath: where you can give a specific size to each item.
you can also set the insets of each section using: sectionInset property.
Important note about the header/footer reference size, when the flow layout scrolls vertically the layout will use the height value to keep the header/footer in that height and stretch the footer to the collection widths. when scrolling horizontally it will do exactly the opposite, it will take the width and stretch on the height.
DataSource implementation:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 50;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 3;
}
As you can see we have 3 sections with 50 items in each section.

Now we'll need to implement a method for the cells:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    SimpleCell *cell = (SimpleCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"SIMPLE_CELL_ID" forIndexPath:indexPath];
    cell.label = [NSString stringWithFormat:@"%d,%d", indexPath.section, indexPath.row];
    cell.transform = CGAffineTransformMakeRotation(arc4random()%1*M_2_PI);
    return cell;
}
So we dequeue a reusable cell with identifier SIMPLE_CELL_ID, same as the cell class we registered before. The cool thing about the UICollectionView is that you dont need to check the if the dequeued cell is null , the collection will instantiate one for you in that case automatically.
Lets provide some final implementation for the supplementary elements:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        HeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HEADER_ID" forIndexPath:indexPath];
        header.label.text = [NSString stringWithFormat:@"Header for section: %d", indexPath.section];
        
        return header;
    }
    else if ([kind isEqualToString:UICollectionElementKindSectionFooter]){
        UICollectionReusableView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FOOTER_ID" forIndexPath:indexPath];
        return footer;
    }
    return nil;
}
same logic as with the cells, we dequeue a supplementary element based on the kind of element and configure it as needed. The result will look like image 4 above.

Customizing your own layout

If the flow layout is not working for you, you can implement your own layout object. you will need to subclass UICollectionViewLayout and implement the following methods at a minimum:
- (void)prepareLayout 
This method is called before the layout is drawn on screen to allow you to prepare any calculations ahead of times.
prepareLayout will also be called when ever the layout is invalidated. Invalidating the layout will throw away all the existing layout information and forces the layout object to start over again. the layout can call this on itself or can trigger this automatically when the bounds change, see shouldInvalidateLayoutForBoundsChange for more details.
- (CGSize)collectionViewContentSize
the second step is to figure out our content size area. here you will tell the UICollectionView what is the size of the content area you will be needing to display all your cells and decorations.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
the last step is supplying an array of layout attributed for the displayed cells in the provided rect.
Since UICollectionView is a subclass of a UIScrollView displays only portion of the items and allows you to scroll to see the rest of the elements. so at any time there is only a certain area provided by the rect that is visible and needing the layout attributes.
6. layout process
Curtesy of Apple.com
UICollectionViewLayoutAttributes
The layout uses objects of class UICollectionViewLayoutAttributes (for short layout attributes) to describe the specific layout attributes for a given item in a collection view. the layout object will create layout attributes as needed by the collection view. Layout attributes include attributes such as frame, center, size, transform3D, alpha, zIndex and hidden.
zIndex is especially useful when cells overlap and you need to provide some order on the z-axis, deciding which cell is displayed on top.
Circular layout Example One of the cool demonstrations at Apple's WWDC 2012 was a circular layout.  Its a layout where the cells are displayed in a circle in the middle of the collection view.
for this layout to work a few things are required from our new custom layout object. we need to know the number of items displayed so we can calculate the angle increment between each cell. which should be done in the prepareLayout method:
- (void)prepareLayout {
    [super prepareLayout];
    //calculate the degree increment
    //360 / items_count
    if (self.numItems) {
        angle = (CGFloat)2*M_PI/self.numItems;
    }
    else{
        angle = 0;
    }
}
Next, we need to provide layout attributes for each cell in the visible rect area. Since we want to display all the cells at once for this demo, we'll provide layout attributes for all of them.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    if (self.numItems == 0) {
        return nil;
    }
    
    CGRect collectionFrame   = self.collectionView.frame;
    CGPoint center = CGPointMake(collectionFrame.size.width/2, collectionFrame.size.height/2);
    
    CGFloat R  = fminf(collectionFrame.size.width, collectionFrame.size.height)/2.0 - 100;
    
    NSMutableArray *array = [NSMutableArray new];
    CGFloat x,y,alpha;
    UICollectionViewLayoutAttributes *attrs;
    int z=0;
    for (int i=0; i<self.numItems; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        alpha = i * angle;
        x = floorf(R * cosf(alpha) + center.x);
        y = floorf(R * cosf(M_PI_2-alpha) + center.y);
        attrs.center = CGPointMake(x, y);
        attrs.size = CGSizeMake(100, 100);
        
        if ((alpha > 0 && alpha <= M_PI_2) || (alpha > 1.5*M_PI && alpha <= 2*M_PI)) {
            attrs.zIndex = z++;
        }
        else if (alpha > M_PI_2 && alpha <= 1.5*M_PI)
        {
            attrs.zIndex = z--;
        }
        [array addObject:attrs];
    }
    
    NSArray *result = [NSArray arrayWithArray:array];
    [array release];
    return result;
}
So above you will see that I iterate over all the items and calculate the (x,y) coordinates of that item on the circle plus some normalization for the items to be positioned in the collection view and then some zIndex calculation to make sure that the cells overlap in a nice way.
Feel free to download the demo project from GitHub at: 
https://github.com/edwardIshaq/CollectionViewDemo

Monday, December 24, 2012

Introduction to NSOperations


NSOperations


Overview
In every software development cycle you will encounter the optimization phase, where you’re app is now doing what it should be doing but the UI is clunky or freezes at some points while the app is doing some heavy lifting work like parsing data, working on database, manipulating images or files etc. These heavy operations if done on the main thread in an iOS app life cycle will block the UI updates and responsiveness of your app. This problem is solved using different methods. You could send some blocks to the background using Grand Central Dispatch (GCD) or spawn your own NSTheads.
NSOperation represents a single unit of computation. It provides you with a thread- safe way to model your workload in aspects of state, priority dependencies and cancelation. So you will be able to subclass NSOperation to customize your own pieces of work in any order/dependency you need to suite your needs for every app you build. It gives an OOP perspective on computation which is a great deal of benefit for today’s complicated requirement and data handling.


Classes


The class structure of the NSOperation is straight forward.
Each Queue type NSOperationQueue will hold a number of operations (NSOperation) .
NSOperation: is an abstract class which you would subclass or use any of its subclasses to execute your work in. Although it is an abstract class it already implements the thread safe features which allows you to focus on the actual work that needs to be done.

NSBlockOperation: is a concrete subclass of NSOperation which allows you to execute several blocks at once with out having to create multiple operations objects. These blocks are dispatched with default priority to an appropriate queue.
NSInvocationOperation: another concrete subclass of NSOperation that allows you to create an operation from a message call or an invocation.
UIActivityItemProvider: a new subclass of NSOperation introduced in iOS 6. When using UIActivityViewController you could pass it a UIActivityItemProvider to provide the item that the activity will be working on. You’re expected to sublclass this proxy object in order to implement your own item for the activity view controller.
All operation objects support the following features:
  • -  support graph-based dependencies between operations.
  • -  Completion block
  • -  KVO
  • -  Prioritizing operations
  • -  Cancelling operations

Creating NSBlockOperation
Creating NSInvocationOperation



Creating NSBlockOperation
Creating NSBlockOperation


Object State
NSOperation state life cycle would normally be: isReady -> isExecuting -> isFinished
isReady: return YES to indicate the operation is ready to start executing unless there is unfinished initialization work that hasn’t been completed yet or a dependant operation hasn’t finished executing yet (more on dependencies later)
isExecuting: return YES if the operation is currently working on its task other wise NO.

isFinished: return YES to indicate that the work has been done.
NSOperation class supports KVC & KVO so you could observe the following keys to control you other parts of your app.
Read-Only properties:
isCancelled, isConcurrent, isExecuting, isFinished, isReady, dependencies

Read-Write properties: queuePriority, completionBlock
if you choose to provide a custom implementation of any of these properties remember that you mush implement the Key-Value-Coding and Key-Value- Observing for these properties.


Cancelation
At some point the user might want to cancel the operation or navigate to some other view controller which at that points renders the operations unnecessary. To cancel the operation you could call [myOperation cancel] a built in method provided by the sdk or you can cancel all the operations on your queue by calling
[myQueue cancelAllOperations] which is also provided by the sdk .
But when the operation starts executing its out of your hands and to enforce the cancelation of an executing operation you need to check your op’s isCancelled property and at that point stop the work and any necessary cleaning up after your code.


Priorities & Dependencies
Another cool feature of NSOperation is dependencies. You should use dependency when your operation can start only after another operation is finished. For example lets say you have image download operation and image processing operation. You want the processing to begin after the image is downloaded. So you can make the image processing operation dependant on the download operation.
[imageProcessingOp addDependency:imageDownloadOp];
[operationQueue addOperation:imageDownloadOp];
[operationQueue addOperation imageProcessingOp];
Always set dependencies before adding the operations to the queue or running them.
This way the imageProcessingOp wont be ready to start until the imageDownloadOp or any other dependencies before it are finished.
For priority management iOS SDK provides this set of priorities to use:
enum {
   NSOperationQueuePriorityVeryLow = -8,
   NSOperationQueuePriorityLow = -4,
   NSOperationQueuePriorityNormal = 0,
   NSOperationQueuePriorityHigh = 4,
   NSOperationQueuePriorityVeryHigh = 8
};
The default priority value is NSOperationQueuePriorityNormal.
You can set the priority of an operation in the Queue by calling the setQueuePriority: method on the op. If you pass a value that isn’t defined the default value will be used (normal priority).
Priorities help order the operations execution order within the queue by promoting high priority operations over low priority ones from the currently ready ops. For example, if you have 2 ops one in Hight priority and the other is Low priority, if the Low priority op is ready before the High priority op it will be executed first. If you want to prevent the low priority op to execute after the high priority op you should make it dependant on the High priority op instead of setting their priority.

Another aspect is the thread priority. Where you can set the thread’s system priority while the op’s main method is executing. Notice that this doesn’t apply for the completion block. You can specify a floating-point value to the threadPriority property before adding it to the queue or executing it manually.


Concurrent Operations
NSOperation object is non-concurrent by default, that means if you run it manually with out adding it to a NSOperationQueue it will run on the same thread where the call was made.
If you run the operations from with in a queue, they will run on background threads synchronously to that thread.

It is possible to make operations run concurrently when ran manually you will have to implement some code on your own to check if the op is ready to run and check if its cancelled periodically and spawn the work on a separate thread on your own.

In this case if the op is not ready you will reschedule a timer to check again later in order to ensure the op actually start executing.


Completion block
In case you want your op to notify listeners or do something at the end that is not considered part of the main method you could set a completion block to be executed once the op is finished.
Call the native method on NSOperation object:

- (void)setCompletionBlock:(void (^)(void))block
the block you pass should take no arguments and should not return any value. Completion block is also used to generate final KVO notifications.
The completion block will execute on the same thread that the operation was running on. So if you want to modify UI make sure to send the call to the main thread.


NSOperationQueue
NSOperationQueue objects are the concrete objects that manage the NSOperation objects you add to the queue.
Creating a queue:
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
Adding operations to the queue is the easiest way to ensure that the operations start. You do so by adding an op to the queue.
[aQueue addOperation:myOperation];
Queues can also be suspended and resumed by your app. Suspending the Queue will prevent new operations from starting, but operations that are currently running will continue until they’re done.
Operations are removed from the Queue when they’re finished.
You also can determine the maximum number or concurrent operations you want your queue to run simultaneously. This helps you better improve your apps performance, especially since operations could potentially consume a lot of memory and processing power. So even though your queuing ops on the queue if the ops are using a lot of CPU and memory your app will suffer from performance issues.



Subclassing NSOperation
When Subclassing NSOperation class you should at least implement the main method. Its recommended to wrap your code there with try..catch clause to be safe of exceptions happening while your operation is running in the background.
While your code is executing, you need to check periodically for any cancellation events in order to stop gracefully.

If your operation must return values to the main thread, it’s a good habit to declare a delegate protocol in order to pass these values back to the main thread and update UI if needed.
[(NSObject *)self.delegate performSelectorOnMainThread:(@selector(delegateMethod:)) withObject:object waitUntilDone:NO];
Note that you will have to cast your operation to NSObject first.
Keep in mind when you change the op’s default properties to execute the appropriate KVC calls to notify listeners about values being changed.
[self willChangeValueForKey:@"isFinished"];
finished = YES;
[self didChangeValueForKey:@"isFinished"];
you should consider using an autorelease pool in the main function to catch any autoreleased objects that you might have used while executing the op.


Demos
Many demos are provided by Apple showing how to subclass NSOperation and things you could do with it.
Please checkout the Apple documentation/Demos at:

NSOperation Class Reference
NSOperationQueue Class Reference
Lazy Table Images ( by Apple)
Demo image downloads and filters (by Soheil Moayedi Azarpour)

Conclusion
NSOperations are a powerful tool for you to model your background work. It’s a little extra overhead than GCD but it comes with the benefits of KVO, suspend/resume, priorities and dependencies.
I recommend reading Concurrency Programming Guide to learn more details about NSOperations and NSOperationQueue tweaks and details.