Sunday, June 22, 2014

HTTP Post with JSON on iOS

Ever since iOS5, the iOS supports the JSON parsing API. The NSJSONSerialization Class could convert JSON to Foundation objects, and convert Foundation objects to JSON. The Foundation objects supported in the API are NSDictionary, NSArray, NSString, NSNumber. (Checkout the Document for detail.)
So, making a HTTP Request on iOS, it requires a NSURLRequest(HTTP Request) configured appropriately, and the NSData to be sent to the server.

1st, Construct the NSData.

NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
[json setValue:[NSString stringWithFormat:@"%d", 2] forKey:@"user_id"];
This piece of code would have a NSDictionary ready with Keys & Values.
NSError *e = nil;
if (![NSJSONSerialization isValidJSONObject:json]) {
    NSLog(@"Invalid JSON format Data");
    return nil;
}

This piece checks if our constructed data is valid to be a JSON object to be converted.
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:&e];
Then, this NSData object data is the data we will need to send to the server.

2nd, Configure the NSURLRequest

    //1, Create NSURLSession.
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil];
    
    //2, Create NSURLRequest
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:4730/adddata"]];

    // 3, Configure the Method of HTTP Request.
    [request setHTTPMethod:@"POST"];
    // 3, Configure the Body(Data) of HTTP Request.    
    [request setHTTPBody:[self postData]];
    // 3, Configure the Header of HTTP Request.    
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    // 4, Create DataTask with Callback function(Block) in it. The block will be fired once the server returns any data to the request.
    NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            // Handle the error;
            NSLog(@"Error: %@", error.localizedDescription);
        }
        NSDictionary* json = [NSJSONSerialization
                              JSONObjectWithData:data
                              options:kNilOptions 
                              error:&error];
        NSLog(@"Error: %@", error.localizedDescription);
        NSLog(@"Response POST: %@", json);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.display.text = [NSString stringWithFormat:@"%@\n%@", json, self.display.text];
        });
    }];

    // 5, Fire the DataTask
    [sessionDataTask resume];
Here, the code
1st, Create a NSURLSession, which will generate a URLTask based on the URLRequest created later.
2nd, Create a NSURLRequest. Since we need to configure the request, then we make it mutable here. The exact URL is the string url, to which is the Restful API of the server.
3rd, Configure the Request with Method, Body(Data) and HTTPHeader.
4th, Create a DataTask which accomplishes the actual request operation. It has a Callback(Block) in it, which will be fired once the request accomplished, data will be received if the server returns any data, like confirmation data, etc.
5th, Fire the DataTask.

Friday, April 11, 2014

iOS Singleton Pattern Under ARC

Singleton Pattern is one of the most famous software design pattern being used in many softwares. It simply and surely always return the same one single instance of a class. It will provide the same instance for whoever need an instance of it.

Basically in Java, if you need a singleton class, you need to define a private static variable, which could be initialized and assigned once. Then, any time other class needs an instance of this class, this class will check if the static instance variable is null or not. If it's not null, return it. Otherwise, initialized and assign it. For more detail, I'd recommend the book <Head First Design Patterns>(This book's code is implemented in Java).

While the problem is how can we implement this design in Objective-C.

Here is the snippet of code.

+ (MyClass *)sharedInstance {
    static MyClass *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

The Apple doc recommends the fowlloing way, which is the same as the one above:

+ (MyClass *)sharedInstance
{
    //  Static local predicate must be initialized to 0
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

Tuesday, April 1, 2014

How to Remove All the Map Annotations except Current User Location Annotation

Today, working on the project focused on Location and Map View Programming. I need to update the Map Annotation Display when user zoom in and out the map. This would totally make sense here the Annotation will not be resizable and too many of the Annotations displayed in a very small area on the Map.

It's like this April Fool's Day, Google Map on mobile device gave people the fun of being a Pokemon Master by finding all the Pokemon, which is displayed as an Annotation on the map. It could be seen only when certain zoom level you are in. So, to find all the Pokemon, you have to zoom to certain level, then search it manually like a tank.

So, the question here is how can we remove these MKAnnotations.

This task is very easy by using one line code:


[self.mapView removeAnnotations:self.mapView.annotations];

The mapView is the outlet connected with MKMapView in the storyboard.

But this line of code would remove all of the annotations on the map. While my app intentionally need to keep the current user location's annotation to constantly display the current location of the user. How can we do that?

We need to iterate through all the annotations, find out which one is not the Current User Location Annotation.


for (id<MKAnnotation> annotation in self.mapView.annotations) {
    if (![annotation isKindOfClass:[MKUserLocation class]]) {
        [self.mapView removeAnnotation:annotation];
    }
}

Simple solution.

Good luck with your own project.

Thursday, February 20, 2014

How to Mark API Method Deprecated

When a developer is required to make his/her own API, after been a while, there is always a chance to rewrite your existing ones, then publish the new ones for the other to use. Here
@interface SomeClass
-method __attribute__((deprecated));
@end
__attribute((deprecated("use xxx method instead.")));
#include <AvailabilityMacros.h>
@interface SomeClass
-method DEPRECATED_ATTRIBUTE;  // or some other deployment-target-specific macro
@end
....

- (void)myDeprecatedMethod __deprecated;
- (int)methodNameDeprecated:(int)param __deprecated;
Works too on classes
__deprecated
@interface MyDeprecatedClass

  // ... some properties and methods ...

@end