Friday, December 9, 2011

NSNotificationCenter Thread Issue

I'm working on a app that uses the UITableView:

I will fetch data from a web server, parse it, and display information in the table.

Code looks like the following (before):

-(void)fetchAndParse
{
    // Fetch and Parse
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kDataRetrieved object:nil userInfo:userInfo];
}

- (void)dataRetrivalSucceeded:(NSNotification *)notification
{
    // Save data

    [myTable reloadData];
}

It was working fine until I decided to put parsing into a separate thread (using NSOperation), data sometimes shows up and sometimes doesn't. The UITableView will load data as usual, or remain blank until I drag it.

Code after:

-(void)fetch
{
    // Fetch

    queue = [NSOperationQueue new];

    NSInvocationOperation *summaryOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseXml:) object:data];

    [queue addOperation:parseOperation];

    [summaryOperation release];
}

-(void)parseXml
{
    // Parse

    [[NSNotificationCenter defaultCenter] postNotificationName:kDataRetrieved object:nil userInfo:userInfo];
}

- (void)dataRetrivalSucceeded:(NSNotification *)notification
{
    // Save data

    [myTable reloadData];
}

And that's when I found out the notification is delivered in the thread in which the notification was posted (Link).
In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
So what I did to make it work is the following:

-(void)fetch
{
    // Fetch

    queue = [NSOperationQueue new];
    NSInvocationOperation *summaryOperation = [[NSInvocationOperation allocinitWithTarget:self selector:@selector(parseXml:) object:data];

    [queue addOperation:parseOperation];

    [summaryOperation release];
}

-(void)parseXml
{
    // Parse

    [[NSNotificationCenter defaultCenter] postNotificationName:kDataRetrieved object:nil userInfo:userInfo];
}

- (void)dataRetrivalSucceeded:(NSNotification *)notification
{
    [self performSelectorOnMainThread:@selector(updateTable:) withObject:notification waitUntilDone:NO];
}

- (void)updateTable:(NSNotification *)notification
{
    // Save data

    [myTable reloadData];
}

The reason data shows after I dragged it is because it calls [myTable reloadData]; on main thread, while I wasn't.

Friday, October 7, 2011

People Who Are Crazy Enough To Think They Can Change The World

I went to the Apple Store at Chandler Fashion Center this noon with some flowers, if I can't be at Cupertino or Palo Alto, an Apple Store is somewhere I can at least visit. It was moving, seeing candles and flowers under the Apple logo, reminds me that photo of people at 1 Infinte Loop cherish the memory of Steve.

Ever since I heard the astonishing news, I wanted to write something, but just don't know where to start from. I'm deeply saddened like many. Never spoken to Steve, not even met him in person, I have a lot personal emotion in that sadness. From my experiences with Apple products dated back to my 3rd grade, to all the stories on how he brought Apple back to business, to my studies and researches that're mostly influenced by Apple's and Steve's design philosophy, I felt a connection between me, Apple, and Steve.

Apple made its way to China with the iPod and the iPhone, but my story with Apple was way back to the late 90s, when I got my first computer, a Macintosh G3. Then PowerBook, Macbooks, iPods and iPhones and many more to come. But it's not only about its products, I started my undergraduate research after transferred to ASU, focus on HCI and user-experiencs studies becuase of Apple. Among all the people, Steve is the one who influenced me the most with his pursuit of perfection in design and user-experiences, I even put "Inspired by Apple’s and Steve's design philosophy and pursuit of perfection, ..." on my resume, and refuse to change it even when I apply at Microsoft.

I see Steve in many differernt roles: An artist, I enjoy using Apple's products that have been engineered to perfection and put user-experiences to the highest priority; A mentor that I've never talked to, but teaches me with all his ideas and products, and eventually leads me, as a computer system major student, became an engineer not only trys to engineering to specification, but trys to engineering to perfection with every end-users in mind; as a person, taught me to stays hungry, stays folish; as a role model, who points me the direction I should be going.

Many people tweeted about this, many people talked, but I cried. You said that the people who are crazy enough to think they can change the world, are the ones who do. You are certainly one of them, and the world would be very different without you. Steve, I miss you. RIP.



Picture's credit to Huilin Dai (website, weibo).

Friday, September 30, 2011

Some Useful Tools

They say school teaches you "how to learn", that's true, but I also believe some tools that aren't covered in any class would be really helpful to mention to help students to get a better coding style, awareness of overlooked errors, as well as good testing skills.

Here's a list of Eclipse plug-ins I recently used a lot in testing my Computer Architecture and O/S classes:

Checkstyle:
http://checkstyle.sourceforge.net/

Findbugs:
http://findbugs.sourceforge.net/

EclEmma:
http://www.eclemma.org/index.html

Metrics:
http://metrics.sourceforge.net/

Friday, September 16, 2011

Subclass NSURLConnection

My recent work involves change two synchronous NSURLConnection to asynchronous, so loading data won't block UI.

I created a custom subclass of NSURLConnection to do this, with a tag I just need to specific the name of that connection at the time I created it, and then checking it while I receive data.

Here's the code:

.h file:

#import <Foundation/Foundation.h>

@interface CustomURLConnection : NSURLConnection {
NSString *tag;
}

@property (nonatomic, retain) NSString *tag;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag;
- (NSString *)tag;

@end

.m file:

#import "CustomURLConnection.h"

@implementation CustomURLConnection

@synthesize tag;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)newTag {
self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately];
if (self) {
self.tag = newTag;
}
return self;
}

- (void)dealloc {
[tag release];
[super dealloc];
}

- (NSString *)tag {
return tag;
}

@end

And I used it like this:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
ALog(@"Connection %@ received data.", [(CustomURLConnection *)connection tag]);
if ([[(CustomURLConnection *)connection tag] isEqualToString:@"someConnection"]) {
[someData appendData:data];
}
else if ([[(CustomURLConnection *)connection tag] isEqualToString:@"someOtherConnection"]) {
[someOtherData appendData:data];
}
}