Sunday, May 31, 2015

Building iOS apps in comand line

Building iOS apps in command line.
1 Using xcodebuild command
Navigate to the directory of the Xcode in the terminal and issue the command xcodebuild. Then you will be able to build. In addition you can specify the build configuration using the –configuration option. For example, this is how to build with debug configuration.
xcodebuild –configuration Debug
2 Building using xctool
Also we can build using the command xctool. In fact xctool can be considered as a replacement for xcodebuild tool. Also xctool is created and maintained by the facebook. In order to install the xctool you need to clone it to some convenient location as follows
git clone git@github.com:facebook/xctool.git

In cloned project, you will see a script called xctool.sh. That is what we should be concentrating.Next you have to build the tool. Fortunately, when you call xctool for the first time, it builds itself. Invoke the the script with with option version as follows. This will give you the current version of the tool. Also it will build the tool.
./xctool.sh -version
Now you need to include xctool installation path to the installation path. So you can easily invoke the command from anywhere else. Now you have the xctool installed and path also correctly set. Now navigate to the folder where your project is residing and issue the xctool command as follows.
xctool.sh -workspace /Your workspace name/ -scheme /Your project name/
There are lot of advantages of using xctool over xcodebuild. One is, output of xctool is better readable. In addition xctool provides different reporters making it easier to integrate CI systems such as jenkins. Also it supports cofiguration file format. In order to use it, simply create a “.xctool-args” file with the following format
[
        "-workspace", "/workspace name/.xcworkspace",
        "-scheme", "/project name/",
        "-configuration", "Release"
]
Because of this file, now you can invoke xctool without other options. But since the xctool is created and maintained by a third party company, xctool may fail with newer xcode versions.
3 Building IPA files with command line
Now you know how to build a xcode project in command line. But in order to run it, you need to create an IPA file. It can be done in command line. It can be done using xcrun tool. xcrun is a xcode tool. It is impacted by the location of the developer directory and the value of $DEVELOPER_DIR environment variable. This tool does two tasks. That is finding development tools and executing them. If you want to find the location of you git installation, you can call this command as follows
xcrun --find git
As I mentioned earlier, this tool can execute tools as well. This is how to execute a git command via xcrun
xcrun git --version
Here you need to be bit carefull. Because xcrun can bypass the traditional $PATH enviroment variable to locate executable files. Now lets get back to our original topic. That is generating the IPA file. It can be achieved with PackageApplication tool. This tool can be invoked by xcrun tool. This is how to invoke it
xcrun PackageApplication
But unfortunately, you will get the following error message.
xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
This error can be caused by either of this issues.
  • It is simply not in your PATH
  • PackageApplication is an executable specific to the iOS SDK. Since we did not specify the SDK we are using and the SDKROOT environment variable was not set, the xcrun was unable to find the tool
We can specify the iOS sdk we are using with the SDK argument.
xcrun --sdk iphoneos --f PackageApplication
Package application only needs the path to the .app package generated at the end of the xcodebuild command line tool. In addition it will perform tasks such as resigning the application before packaging it into the IPA file. Path to the generated package can be found at the end of the command's output. This is how to use it
/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${RELEASE_BUILDDIR}/${APPLICATION_NAME}.app" -o "${BUILD_HISTORY_DIR}/${APPLICATION_NAME}.ipa" --sign "${DEVELOPER_NAME}" --embed "${PROVISONING_PROFILE}”
Putting everything in a single script
Now you have scene how to build and generate IPA files in command line. In a CI environment it is better to have them in a single script. This is how to do it.
#!/bin/bash
WORKSPACE="/Your workspace name/"
SCHEME="/Your project name/"
BUILD_DIR="$(pwd)/build"
CONFIGURATION="Release"
ARCHIVE_FILENAME="/Your project name/.app"
IPA_FILENAME="/Your project name/.ipa"
security unlock-keychain -p $PASSWORD $HOME/Library/Keychains/login.keychain

xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -configuration
CONFIGURATION_BUILD_DIR="$BUILD_DIR" clean build | xcpretty -c
xcrun -sdk iphoneos PackageApplication "$BUILD_DIR/$ARCHIVE_FILENAME" -o "$BUILD_DIR/$IPA_FILENAME"

For any query, feel free to contact me via my linkedin profile.

Friday, May 1, 2015

Defining a service layer with AFNetworking

This example shows how to create a service layer for json based web services. This is how I developed it.
  1. Create a basic interface for calling web services
  2. Create a subclass of correct AFNetworking seralizer class(in this case AFJsonSerializer) and format the response
  3. For each web service create a singleton subclass of AFHttpSessionManager
  4. Create a Façade for service layer
For this example I am using free web service used used by raywenderlich afnetworking tutorial

1 Creating basic interface
In modern software engineering, we write code for the interface, not for the implementation. So create a protocol named Service as folows
@protocol Service <NSObject>

- (void)callService:(NSDictionary*)parameters withCompletionBlock:(void(^)(NSArray *resultArray, NSError *error))completionBlock;

@end

This has a method called callService and it is the method used to call the web services. Now we have an interface, which can be used to call web services. I will explain the importance of this when we actually call a web service.

2 Creating a custom json response serializer
Here, we get the response in json format. we need to process this json response in order to get the correct result out of it. For that purpose we can create a subclass of the AFJSONResponseSerializer class and override it's responseObjectForResponse as follows. This method is overridden according to the json response we get. This method directly create models from the response and add it to an array
@implementation WeatherServieJasonSerializer

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error {
    NSMutableArray *retArray = [[NSMutableArray alloc] init];
    NSDictionary *json = [super responseObjectForResponse:response data:data error:error];
    NSDictionary *dictionary = json[@"data"];
    WeatherInfo *infoRet = [[WeatherInfo alloc] init];
    NSArray *arrData = dictionary[@"weather"];
    
    infoRet.tempMaxC = @([((NSString*)((NSDictionary*)arrData[0])[@"tempMaxC"]) integerValue]);
    infoRet.tempMaxF = @([((NSString*)((NSDictionary*)arrData[0])[@"tempMaxF"]) integerValue]);
    infoRet.tempMinC = @([((NSString*)((NSDictionary*)arrData[0])[@"tempMinC"]) integerValue]);
    infoRet.tempMinF = @([((NSString*)((NSDictionary*)arrData[0])[@"tempMinF"]) integerValue]);
    
    [retArray addObject:infoRet];
    
    return retArray;
}
@end
 
3 Creating a singleton subclass of AFHttpSessioManager to invoke web services.
For each web service you have, you need to create a separate class like this. In addition this class conform to the Service protocol and implements its callService method. Following is the code for the class.
.h file
#import "AFHTTPSessionManager.h"
#import "Service.h"

@interface WetherWebService : AFHTTPSessionManager<Service>

+ (WetherWebService*)getSharedInstance;

@end

.m file
#import "WetherWebService.h"
#import "WeatherServieJasonSerializer.h"

static NSString * const baseURLString = @"http://www.raywenderlich.com/demos/weather_sample/";

@implementation WetherWebService

+ (WetherWebService*)getSharedInstance {
    static WetherWebService *sharedInstance = nil;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedInstance = [[WetherWebService alloc] initWithBaseURL:[NSURL URLWithString:baseURLString]];
        sharedInstance.responseSerializer = [WeatherServieJasonSerializer serializer];
    });
    
    return sharedInstance;
}

- (void)callService:(NSDictionary*)parameters withCompletionBlock:(void(^)(NSArray *resultArray, NSError *error))completionBlock {
    [self GET:@"weather.php" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
        completionBlock(responseObject, nil);
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        completionBlock(nil, error);
    }];
}

@end
 
4 Creating the service layer façade.
This is an implementation of façade design pattern. This creates an abstraction layer between the web service layer and the rest of the application. This is the source of ServiceLayerFacade.h file
@interface ServiceLayerFacade : NSObject

+ (ServiceLayerFacade*)getSharedInstance;
- (id<Service>)getWeatherService;

@end
#import "ServiceLayerFacade.h"
#import "WetherWebService.h"

@implementation ServiceLayerFacade

+ (ServiceLayerFacade*)getSharedInstance {
    static ServiceLayerFacade *sharedInstance = nil;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedInstance = [[ServiceLayerFacade alloc] init];
    });
    
    return sharedInstance;
}
- (id<service>)getWeatherService {
    return [WetherWebService getSharedInstance];
}
This is how these web services should be called.
NSDictionary *parameters = @{@"format": @"json"};
    ServiceLayerFacade *serviceLayer = [ServiceLayerFacade getSharedInstance];
    id<Service> weatherWebService = [serviceLayer getWeatherService];
    [weatherWebService callService:parameters withCompletionBlock:^(NSArray *resultArray, NSError *error) {
        if (resultArray[0] != nil) {
            id<Tablelayout> tableModel = resultArray[0];
            _tableArray = [tableModel getTableRepresentation];
            [_weatherTable reloadData];
        }
    }];
Here, since we are using interfaces and a facade, we can completely hide the implementation details of the web service layer. Web service caller only knows of the uniform interface method to call the web service. He does not know the classes used to call the web service, the way response is processed etc. What he gets is model classes that can be directly used in his code. Now I will explain the beauty of this approach. We use Service interface to access the web service. And we do not know how the web service is called behind the scene and how the response is processed. Because of this we can change everything related to web service calling and processing without affecting rest of the layers.

Presenting the data
This is our model class
#import 

@interface WeatherInfo : NSObject

@property NSNumber *tempMaxC;
@property NSNumber *tempMaxF;
@property NSNumber *tempMinC;
@property NSNumber *tempMinF;

@end
Now we have the data retrieved from the web service stored in our model classes. Now how to present it? You can add a method to the model class to get some sort of array and show it in a table. But this is an extremely bad idea. Because a model class should not know how the data is presented. So here our basic problem is adding behavior to the model object, without affecting behavior of other objects from the same class. What is the design pattern we can use to achieve this? The answer is decorator pattern
 
Implementation of decorator pattern
I normally use categories to implement decorator pattern in objective c. In addition I declare category methods in a protocol as well. This protocol acts as an interface
#import 

@protocol TableLayout <NSObject>

-(NSArray*)getTableRepresentation;

@end

This is the category of the model class.
.h file
#import "WeatherInfo.h"
#import "TableLayout.h"

@interface WeatherInfo (TableRepresentation)<TableLayout>

@end

This is the .m file
#import "WeatherInfo+TableRepresentation.h"

@implementation WeatherInfo (TableRepresentation)

-(NSArray*)getTableRepresentation {
    return [[NSArray alloc] initWithObjects:self.tempMaxC,self.tempMaxF,self.tempMinC,self.tempMinF, nil];
}

@end
Then in code via the TableLayout interface I am getting the table representation as follows.

id<Tablelayout> tableModel = resultArray[0];
            _tableArray = [tableModel getTableRepresentation];
            [_weatherTable reloadData];
This is how I implemented the service layer. The complete example of this tutorial is available in GitHub.

Alternative approaches
  • This stackoverflow question presents few ways of developing a service layer using AFNetworking and ReactiveCocoa
  • You can use RestKit to get Core data models directly after web service calls

For any query, feel free to contact me via my linkedin profile. Happy coding!!!!

Tuesday, April 7, 2015

Usnig dispatch_apply with asyncronuos functions

Usually dispatch_apply is a synchronous function, which will pause the current thread, then execute the block and return to the paused thread. See the following example
Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 );
dispatch_apply(10, queue, ^(size_t index) { 
NSLog(@"%zu", index); }); 
NSLog(@"done");
The results is as follows











But this is a synchronous execution. Assume you have a NSMutableArray and you need to perform some action for each of the object in array asynchronously in a separate thread, this is how to do it. Also since this is executed in a global dispatch queue, you cannot guarantee which block runs first.
//first get a  global dispatch queue
dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
//Then add an asynchronous block
dispatch_async(queue, ^{ 
 //inside this block, you can use dispatch_apply
dispatch_apply([array count], queue, ^(size_t index) { 
//your block code goes here.
}); 
//Now you block has finished. You can execute some other task here.
});

  For any query, feel free to contact me via my linkedin profile.

Wednesday, March 25, 2015

Thread safe Queue in objective C with GCD

There are several methods we can use to make a class thread safe in objective c. They are
  1. Using NSLock
  2. Using @synchronized block
  3. GCD

Among them GCD is the easiest and safest way. Because unlike other two approaches GCD manages many of exception for us and it is easy to use. Also GCD is recommended by apple over other two options.
#import "ThreadSafeQueue.h"

@interface ThreadSafeQueue()

@property (strong, nonatomic) NSMutableArray *queueData;
@property (strong, nonatomic) dispatch_queue_t dataQueue.

@end

@implementation ThreadSafeQueue

- (instancetype)init {
    if (self = [super init]) {
        _dataQueue = dispatch_queue_create("deltaaruna.ThreadSafeQueue", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

- (id)dequeue {
    __block id result = nil;
    dispatch_sync(self.dataQueue, ^{ 
    if(self.queueData.count > 0) {
     result = [self.queueData[0]] 
    }
    });
    return result;
}

- (NSUInteger)length {
    __block NSUInteger result = 0;
    dispatch_sync(self.dataQueue, ^{ result = [self.queueData count] });
    return result;
}

- (void)enqueue:(id)obj {
    dispatch_barrier_async(self.dataQueue, ^{ [self.queueData addObject:obj] });
}

@end

For any query, feel free to contact me via my linkedin profile.

Monday, February 2, 2015

Autolayouting for dynamically changing views in iOS(with complex UITableViewCells and UIButtons)

I have used both IB based and code based approach with autolayout. If the view is static the solution is very easy. You can use the easiest way, the IB based autolayouting. But if the view is dynamic, I have used code base and IB based approach plus few tricks.
Consider following screen shots

First image is taken when device is in landscape mode and second image is taken when the device is in portrait mode. Now consider the image that contains a camera, which is located at top right corner. Actually it is a UIButton with an image. If you examine carefully you will notice that the top inset of the element in the landscape mode is much lower that the in the potrait mode. This is how I implemented it.
  • Add left insets in the interface builder
  • programmatically add top insets according to the orientation
  • When the orientation change programmatically change the top insets and call setNeedsUpdateConstraints method on that view

Add these two constants in after #import section
static int buttonTopinsetLandscape = 1;
static int buttonTopinsetPotrait = 14;


- (void) adjustViewsForOrientation {
    [self addInsets];
    [photoBtn setNeedsUpdateConstraints];
}

- (void) addInsets {
  self.constraint = [NSLayoutConstraint constraintWithItem:photoBtn
         attribute:NSLayoutAttributeTop
         relatedBy:NSLayoutRelationEqual
            toItem:self.view
         attribute:NSLayoutAttributeBottom
        multiplier:1.0
          constant:[self getButtonTopinset]];

  [self.view addConstraint:constraint];
}

- (int)getButtonTopinset {
    return [self returnCurrentInset:buttonTopinsetLandscape withPotrait:buttonTopinsetPotrait];
}

- (int)returnCurrentInset:(int)landscape withPotrait:(int)potrait {
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        return potrait;
    } else if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        return landscape;
    } else {
        return potrait;
    }
}


In viewwillappear method add notification to listen to orientation changes as follows.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(adjustViewsForOrientation) name:UIDeviceOrientationDidChangeNotification object:nil];

That's cool right? lets move in to much complex example. Look at the following table view.
---UPDATE---- The example for this part of the tutorial is now available on GITHub as well.
Each cell has different number of UIImageViews from one to four. Number of UIImageViews to be displayed can only be determined at run time. And the each cell changes the image view dimensions according to orientation. Here I have to use code based approach. I have used VFL here.
When there are two image Views
NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne,imgViewTwo);
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-4-[imgViewOne(imgViewOne)]-5-[imgViewTwo(imgViewOne)]-3-|" options:0 metrics:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewOne]-88-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewTwo]-88-|" options:0 metrics:nil views:views]];

Here image views share the same width. Here they will retain there left and right insets to the superview and adjust their widths accordingly.
When there are three image Views

[cell.contentView addSubview:imgViewOne];
            [cell.contentView addSubview:imgViewTwo];
            [cell.contentView addSubview:imgViewThree];
            
            imgViewOne.translatesAutoresizingMaskIntoConstraints = NO;
            imgViewTwo.translatesAutoresizingMaskIntoConstraints = NO;
            imgViewThree.translatesAutoresizingMaskIntoConstraints = NO;
            
            NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne, imgViewTwo, imgViewThree);
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-4-[imgViewOne(imgViewOne)]-5-[imgViewTwo(imgViewOne)]-3-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-4-[imgViewOne(imgViewOne)]-5-[imgViewThree(imgViewOne)]-3-|" options:0 metrics:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewOne]-88-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewTwo(imgViewTwo)]-5-[imgViewThree(imgViewTwo)]-88-|" options:0 metrics:nil views:views]];
Here please note that width of image views are similar and height of imgViewThree and imgViewTwo are similar
When there are four image Views
NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne, imgViewTwo, imgViewThree, imgViewFour);
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-4-[imgViewOne(imgViewOne)]-5-[imgViewThree(89)]-5-[imgViewFour(89)]-3-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-4-[imgViewOne(imgViewOne)]-5-[imgViewTwo(182.5)]-3-|" options:0 metrics:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewOne(178)]-88-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewTwo(115.5)]-5-[imgViewThree(58)]-88-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-95-[imgViewTwo(115.5)]-5-[imgViewFour(58)]-88-|" options:0 metrics:nil views:views]];
            [imgViewTwo setContentHuggingPriority:200
                                        forAxis:UILayoutConstraintAxisHorizontal];
            [imgViewOne setContentHuggingPriority:252
                                        forAxis:UILayoutConstraintAxisHorizontal];
            [imgView3 setContentHuggingPriority:200
                                        forAxis:UILayoutConstraintAxisHorizontal];
            [imgView4 setContentHuggingPriority:200
                                        forAxis:UILayoutConstraintAxisHorizontal];
Looks cool right? But not good enough. Here for example width of each imageview is the same. But what if you need one imageview is three times of the second one? If you try to achieve this with VFL you will get a run time exception. The only way is hard coding the widths which is an extremely bad idea. Then you will have hard time when you deal with different screen sizes and orientations. So VFL is not a viable solution at all.
We still have one option left for autolayoiting. That is using pure objective C based approach without using VFL. Then we can change the height and width of each image more freely.
Assume when you have three images width of the first image is three times the width of the second and third images this is how you should change the code. And when there are four images, width of the first image is three times the width of the second image and six times the third and fourth images
//for one image
NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne);
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-|" options:0 metrics:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewOne]-5-|" options:0 metrics:nil views:views]];

//for two images
NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne,imgViewTwo);
            
             [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-[imgViewTwo(imgViewOne)]-5-|" options:0 metrics:nil views:views]];
            
           [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewOne]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewTwo]-5-|" options:0 metrics:nil views:views]];

//for three images
NSLayoutConstraint *ratioCons =[NSLayoutConstraint
                                               constraintWithItem:imgViewOne
                                               attribute:NSLayoutAttributeWidth
                                               relatedBy:NSLayoutRelationEqual
                                               toItem:imgViewTwo
                                               attribute:NSLayoutAttributeWidth
                                               multiplier:3
                                               constant:0];
            
            [cell.contentView addConstraint: ratioCons];
            
            NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne, imgViewTwo, imgViewThree);
            
            // Horizontal layout - note the options for aligning the top and bottom of all views
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-[imgViewTwo]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-[imgViewThree]-5-|" options:0 metric
s:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewOne]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewTwo]-5-[imgViewThree(imgViewTwo)]-5-|" options:0 metrics:nil views:views]];

//for four images
NSLayoutConstraint *ratioConsOne =[NSLayoutConstraint
                                            constraintWithItem:imgViewOne
                                            attribute:NSLayoutAttributeWidth
                                            relatedBy:NSLayoutRelationEqual
                                            toItem:imgViewTwo
                                            attribute:NSLayoutAttributeWidth
                                            multiplier:3
                                            constant:0];
            
            NSLayoutConstraint *ratioConsTwo =[NSLayoutConstraint
                                               constraintWithItem:imgViewOne
                                               attribute:NSLayoutAttributeWidth
                                               relatedBy:NSLayoutRelationEqual
                                               toItem:imgViewThree
                                               attribute:NSLayoutAttributeWidth
                                               multiplier:6
                                               constant:0];
            
            NSLayoutConstraint *ratioConsThree =[NSLayoutConstraint
                                               constraintWithItem:imgViewOne
                                               attribute:NSLayoutAttributeWidth
                                               relatedBy:NSLayoutRelationEqual
                                               toItem:imgViewFour
                                               attribute:NSLayoutAttributeWidth
                                               multiplier:6
                                               constant:0];
            
            [cell.contentView addConstraint: ratioConsOne];
            [cell.contentView addConstraint: ratioConsTwo];
            [cell.contentView addConstraint: ratioConsThree];
            
            NSDictionary *views = NSDictionaryOfVariableBindings(imgViewOne, imgViewTwo, imgViewThree, imgViewFour);
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-[imgViewTwo]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-5-[imgViewOne(imgViewOne)]-5-[imgViewThree]-5-[imgViewFour]-5-|" options:0 metrics:nil views:views]];
            
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewOne]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewTwo]-5-[imgViewThree(imgViewTwo)]-5-|" options:0 metrics:nil views:views]];
            [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-5-[imgViewTwo]-5-[imgViewFour(imgViewTwo)]-5-|" options:0 metrics:nil views:views]];

Here I am using the pure objective c based approach along with VFL. Actually pure objc approach alone could have been used. I have mixed both the approach since it clearly shows the limitations of the VFL. In some dynamic UIs we have to use pure code based appproach. This example nicely shows it. But use of either VFL or objective c code approach result in verbose code. So in order to keep the code base nice and clean, many use wrappers around autolayout API. My personal preference is keeplayout library. I have extensivly used it and I would highly recommend it.
---UPDATE---- The example for this part of the tutorial is now available on GITHub as well.
For any query, feel free to contact me via my linkedin profile.

Monday, January 5, 2015

Dynamically changing rotation in iOS

I had a requirement to dynamically enable and disable the rotation of an iOS. We had a navigation controller throughout the app. First you need to enable landscape and potrait mode using Xcode. You can specify this in the deployment info section in the XCode
When we dynamically change the rotation, we need to change the rotation not only in the viewcontroller, but also in the navigation controller. Next you need to create a category of UINavigationController which supports for dynamic orientation changes. Here you need to overide two methods

-(bool)shouldAutoRotate and -(NSUInteger)supportedInterfaceOrientation
This is how they were overridden.



We need a boolean instance variable to determine whether we should rotate or not. Here. I have used iOS run time programming to assign value for this boolean value. Because we can't synthasis instance variables in a category. Also I am using a NSNumber variable instead of a boolean primitive.



Here KNewProertyKey is declared as follows


When you need to enable or disable rotation you just need to set the status with setRotationStatus method.
After that we can dynamically enable and disable the rotation. For any query, feel free to contact me via my linkedin profile.

Tuesday, November 4, 2014

Concurrency problems in singleton design pattern - An objcective c example

Singleton pattern is a very common pattern in iOS. It is one of the easiest to understand. But if you do not fully consider the concurrency, you will come across bugs which are extremely difficult to find. Have a look the following code which looks completely normal.
+ (instancetype)sharedInstance    
{
    static SomeClass *obj = nil;
    if (!obj) {
        obj = [[SomeClass alloc] init];
    }
    return obj;
}
Looks normal right? But really it is not the case.
Here the if condition branch is not thread safe. If this method is invoked with multiple threads, this may happen. Assume you have two threads(A and B). Now A enters the if block and a context switch occurs before
obj = [[SomeClass alloc] init];
is executed. Next thread B enters the if block and allocates an instance of the singleton and exit. Then thread A gets the chance. It also starts inside the if block and creates the instance. Now you have two instances. Clearly this is not what you need in singleton pattern.

Solution
+ (instancetype)sharedIinstance
{
    static SomeClass *obj = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        obj = [[SomeClass alloc] init];
    });
    return obj;
}

Here dispatch_once() executes the block only a one time in a thread safe manner. So different threads will not be able to access the critical section as I showed earlier.
This is not the only problem with singleton. Here only instantiation is thread safe. A Class may have mutable objects. In that case we need to consider about the thread safety status of those objects. Otherwise reader writer problems may occur.
Assume you have a NSMutableArray inside the singleton class and you have read and write operations in to that NSMutableArray object. you need to do two things in order to ensure thread safety. Here there is a possibility for a reader/writer problem scenario.
What is the reader/writer problem?
Assume you are going to make an online purchase and there is only one item left. As long as you are doing only read operations it is ok. But if you do any database write operations there may be problems. If someone completes a transaction while you are doing the transaction a problem will occur. It is called the reader/writer problem.
With apple GCD we have a very easy solution for that. GCD has an implementation of a reader/writer queue. GCD manages everything for us. A dispatch barrier creates a synchronization point inside a concurrent dispatch queue. GCD ensures that the submitted block is the only item executed on the specified queue for that particular time. All items submitted to the queue prior to the dispatch barrier must complete before the execution of the block. After the block is finished queue returns to the its specified implementation.
We have a NSMutableArray as follows.
@property (nonatomic, strong) NSMutableArray array;

And read and write operations as follows.
- (void)addObject:(NSObject *)obj
{
    if (obj) {   
     [_array addObject:obj]; 
    }
}

- (NSArray *)getObj
{
    NSArray *array = [NSArray arrayWithArray:_array]; 
    return array;
}

Add this to the header file
@property (nonatomic, strong) dispatch_queue_t concurrentQueue;

Then when you add to the NSMutableArray instance, the adding object operation should be added with a dispatch barrier.
- (void)addObject:(NSObject *)obj
{
    if (photo) { 
        dispatch_barrier_async(self.concurrentQueue, ^{  
            [_array addObject:obj]; 
        });
    }
}

Also when you read data from the mutable array also you should do it via a serially dispatched block as follows.
- (NSArray *)getObj
{
    __block NSArray *array; 
    dispatch_sync(self.concurrentQueue, ^{ 
        array = [NSArray arrayWithArray:_array]; 
    });
    return array;
}

Now your singleton is thread safe!! For any query, feel free to contact me via my linkedin profile. Happy coding!!!