Thursday, June 14, 2012

Using NSFileHandle.writeabilityHandler

I am using [NSFileHandle writeData:] to send data over network in one of my projects, and I found an interesting problem when I run the app with the testing device, which is using iOS 5.1. After 100 bytes of data are sent, the writeData method halts and throws an exception. Results from Google search told me that it is a problem since iOS 5.0, and maybe I should use NSFileHandle.writeabilityHandler, which is introduced since iOS 5.0 / MacOSX 10.7, instead. Unfortunately, I could not find a single example on web about how to use NSFileHandle.writeabilityHandler should be used. After a day of trial-and-error I finally figured out a workable solution, and I will put it here as a reference. However, I must say this solution is only workable, but not elegant, not even close. I believe there must be a better solution than mine out there.

Update:
  • It seems that fileDescriptor can be used directly in send() or sendto()
  • It is better to use send() which will not block this thread
  • Updated the code to end the sending if there is sending error

// Some definitions
BOOL isAtOrAboveIOS5 = [yourfileHandle respondsToSelector:@selector(setWriteabilityHandler:)];
NSMutableData* pendingData = [[NSMutableData alloc] initWithCapacity:1024];

// Try to send data here
// iOS 5 / OSX 10.7 or above
if (isAtOrAboveIOS5 == YES) {
    [pendingData appendData:dataToSend];
    remoteFileHandle.writeabilityHandler = ^(NSFileHandle* thisFileHandle)
    {
        int amountSent = send([thisFileHandle fileDescriptor], [pendingData bytes], [pendingData length], MSG_DONTWAIT);
        if (amountSent < 0) {
            // errno is provided by system
            NSLog(@"Error while sending response: %d", errno);
            amountSent = [pendingData length];
        }
        [pendingData replaceBytesInRange:NSMakeRange(0, amountSent) withBytes:NULL length:0];

        // Finishing
        if ([pendingData length] == 0) {
            thisFileHandle.writeabilityHandler = nil;
        }
    };
} else { 
    [yourfileHandle writeData:dataToSend];
}

My guess of the actual problem when using writeData: after iOS 5.0 is that writeData: just tries to send as much data as possible over the socket in one shot. If there is much data than the socket can accept (this time), exception is thrown. With NSFileHandle.writeabilityHandler set, the code block is executed everytime its fileDescriptor (this time it is a socket) can accept more data. Since there is no method in NSFileHandle which tells you how many data is actually written, I used function sendto() here, but I believe there should be a better implementation exists.

Monday, June 4, 2012

Updating UIView inside function observeValueForKeyPath:ofObject:change:context:

This time, I try to observe change of a value using KVO and update UI after a specific change, in iOS. I put the code of UI updates inside observeValueForKeyPath function like the following:
- (void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if (object == targetObject && [keyPath isEqualToString:@"targetKeyPath"]) {
        if (targetObject.targetKeyPath == targetValue) {
            // self is a pointer of UIViewController
            [self.view setBackgroundColor:[UIColor blackColor]];
            NSLog(@"UI Update Here!!!");
        }
    }
}

It turns out the background color does not change as planned but the log is printed. I am sure the UIViewController is the top view controller so it is not view-controller-is-not-top-view-controller-problem as some Google results teach me. I was frustrated and tried my best to Google for a few hours without luck. Finally, an example in iOS Developer Library gave me a huge hint. In that example, its author put this line of code inside observeValueForKeyPath function, just before lines which will update a table view.
assert([NSThread isMainThread]);

I placed this line in my code and the assertion failed. I couldn't help but think: Is there any relationship between "Updating UI" and "Main Thread"? It turns out to be a huge YES. Check out this paragraph in UIView Class Reference.

Threading Considerations

Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.
At this point, the root cause of the problem becomes clear:
  1. The observeValueForKeyPath function does not run in main thread. (Maybe it does run on the main thread sometimes, but we have no control anyway)
  2. Any UI manipulations must occur on the main thread
Knowing these, solving the problem becomes easy:
- (void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if (object == targetObject && [keyPath isEqualToString:@"targetKeyPath"]) {
        if (targetObject.targetKeyPath == targetValue) {
            // self is a pointer of UIViewController
            [self.view performSelectorOnMainThread:@selector(setBackgroundColor:)
                                        withObject:[UIColor blackColor]
                                     waitUntilDone:NO];
            NSLog(@"UI Update Here!!!");
        }
    }
}

Finally it works like magic :)

Sunday, March 25, 2012

Lock-free Queue (Single Producer Single Consumer)

I was searching for an efficient thread-safe queue implementation last week for my project at work, and I came up with the term "Lock-free Queue". It seems to be already a widely studied topic (Google suggested me a few papers) but I think they are too difficult to understand. After that I found this page which introduced and explained the author's lock-free queue implementation. Although it has certain limitations (only one producer and one consumer are allowed), its implementation is very simple and I think the author's explanation is simple and clear. What's more, it fits my case (even with those limitations).

For my own reference, I put part of my code (a little bit modified from what's described by the author) below. With CUSTOM_QUEUE_NODE_REUSE flag, the enqueue function will not do the lazy removal as the author suggested. Instead it directly reuses nodes which were previously dequeued. The drawback of this modification is the actual memory usage of the queue will always be the same as when it reached its longest queue size.

Update: Since C++ increment and decrement operations are not atomic and it causes bug in the code below, I removed the related code. If one needs to deal with queue size, he has to find atomic functions for increment and decrement.

Tuesday, March 6, 2012

Working with JSON using C# (.NET 3.5 or above)

Using .NET framework 3.5 or above, one can manipulate JSON object using a JavaScriptSerializer. To do so:
  1. Adding .NET reference System.Web.Extensions
  2. Use namespace System.Web.Script.Serialization
  3. Create appropriate classes to describe the target JSON structure
The following example demonstrates how to read from and write to a JSON object.

Note: The JSON string used below is adopted from web.

P.S. In C#, two double quotes are used to describe one double quote in a multi-line literal (string), all escape characters (e.g. \") does not work in this case