Tuesday, April 22, 2014

How the XIB resource item connect to IBOutlet or IBAction


The below is a typical code when using xib resource from a IBOutlet property, however, notice the strange thing in headerView property, inside the if block, it just loads the nib file, but not assign the value of _headerView, so how the variable is magically assigned when XIB (nib) resource is loaded?

@interface BNRItemsViewController ()
@property (nonatomic, strong) IBOutlet UIView *headerView;
@end

@implementation BNRItemsViewController
- (UIView *)headerView
{
    // If you have not loaded the headerView yet...
    if (!_headerView) {

        // Load HeaderView.xib
        NSArray* arr = [[NSBundle mainBundle] loadNibNamed:@"HeaderView"
                                      owner:self
                                    options:nil];
    }

    return _headerView;
}
@end

The magic happens with the HeaderView.xib's File Owner settings, in headerview.xib, the file owner is set to BNRItemViewController, in addition, the fileOwner's (i.e BNRItemViewController's headerView property is associated to the UIView control in the xib resource. As a result, when loadNibNamed:owner:options is called, after the resource is loaded into memory, it sets the file owner as self (i.e. currrent BNRItemViewController), and then set the headerView IBOutlet property to the UIView resource item. So the property will be automatically assigned to a loaded uiview instance.

you have now seen that a XIB file can be used any time on any class set to its Files' Owner, any object can load a XIB file manually by sending the message loadNibNamed:owner:options: to the application bundle to associate the resouce with its properties.

Note that a UI control in xib file may also need a delegate to handle its event, this is done by control drag the control to file's Owner, so it specifies whatever object works as file's owner will need to handle the uiview's event.

Thursday, April 17, 2014

Define private property, instance variable and method in objective c

In addtion to public property and method,  public, protected, and private instance can also be defined in objective C header files, and the public and protected instance variable can be accessed by object->instanceVariable from other class or its subclass. Within the same class implementation, the private instance can be accessed either using self->privateVariable or privateVariable directly. The recommended way is self->privateVariable to avoid mixing with local variable with the same name.

Private method, property and instance variable that should not be exposed by header file should be defined in implementation .m file. The class extension can be used to define private property and private method. But private instance variable has to be defined different.

The below sample .h and .m file includes the most common usage

Header file
@interface TestObj : NSObject{
//define instance variables in header file
@public
    NSString* publicInstanceVariable;
@protected
    NSString* protectedInstanceVaraible;
@private
    NSString* privateInstanceVarialble;
}

//define public property
@property (readwrite) NSString* publicProp;

//define public methods
-(NSString*) getPublicProp;
-(void)setInstanceVariable:(NSString*)var;
-(void)setPrivatePropMethod:(NSString*)var;
-(NSString*)getInstanceVariable;
-(NSString*)getPrivateProp;
-(NSString*)callPrivateMethod:(NSString*)parm;
@end

Implementation file
#import "TestObj.h"

@interface TestObj()
    //define private property
    @property NSString* privateProp;

    //define private method
    -(NSString*) privateMethod:(NSString*)parm;
@end

//define private instance variable in .m file
@implementation TestObj{
    NSString* privateInstanceVariable;
}

//implement private method
-(NSString*) privateMethod:(NSString*)parm{
    self->privateInstanceVariable = parm;
    return self->privateInstanceVariable;
}

//implement public method
-(NSString*) getPublicProp{
    return self.publicProp;
}

-(void)setInstanceVariable:(NSString*)var{
    self->privateInstanceVariable = var;
}

-(void)setPrivatePropMethod:(NSString*)var{
    self.privateProp = var;
}

-(NSString*)getInstanceVariable{
    return self->privateInstanceVariable;
}

-(NSString*)getPrivateProp{
    return self.privateProp;
}

-(NSString*)callPrivateMethod:(NSString*)parm{
    return[self privateMethod:parm];
}

@end

Note: class extension is a special case of category without a name; that is, no name is specified between
the ( and ) . class extension can extend the class by adding additional private properties. This is not allowed for named categories

Wednesday, April 16, 2014

Notes for using ios NSURLProtocol

1. If multiple nsurlprotocol is registered, the last one registered will be called first for canInitWithRequest method to check whether it can handle the request.

2. It is understandable that registered nsurlprotocol is consulted when loading a request. but what exactly is "loading a request". Actually, it means when create a new NSUrlConnection object instead of a new NSURLRequest boject. That is the reason why canonicalRequestForRequest can create a new request object without triggering the canInitWithRequest be called again.

3.NSURLProtocol.client represents the receiver who initialized the original request, and who expect to receive response data from NSURLProtocol instance if true was returned by the the instance. The receiver makes itself accessible through NSURLProtocol.client property with NSURLProtocolClient protocol.

4. When NSURLProtocol handles a request, it may need to create a new nsurlconnection instance to get server response, the new nsurlconnection instance will send out the new query to all registered NSUrlProtocol instance, and if the same NSUrlProtocol return true on its canInitWithRequest method, it will lead to an infinite loop. Usually this is handled by adding a particular flag in the request object by calling NSUrlProtocol's setProperty and propertyForKey method. So if the flag already exists, just skip it and let the NSURLConnection's default implementation to handle the request.

5. When a web request was sent from ios UIWebView, NSUrlProtocol.canInitWithRequest may be called multiple times for the same request. However, initWithRequest and startLoading should only be called once when the URL Loading system asks the selected NSUrlProtocol to process the request.

6. It is possible to chain multiple NSURLProtocol to handle the same request, the key is the lower level NSUrlProtocol's connection handler must call its NSUrlProtocol.client delegate method to pass the information to other NSUrlProtocol instances. For example, if one NSUrlProtocol instance does not know how to handle an authentication challenge, it should still return true to canAuthenticateAgainstProtectionSpace method, and then call
[[self client] URLProtocol:self didReceiveAuthenticationChallenge:challenge ];
method to let other NSUrlProtocol instance to handle it.

7. Be careful when deciding what scope to define properties or instance variables when implementing NSUrlProtocol, If the information is per request, then it should be defined as instance property or variable in NSUrlProtocol. However, there is no easy way to define per webview or per page variables as NSUrlProtocol alloc method is called from ios sytem, not the application code.

Friday, April 11, 2014

Dispatch queue, Operation queue difference

Both dispatch queue and operation queue in Grand Central Dispatch (GCD) are available for ios development for handling asynchronous operation, and each has its own features.

Operation queue is a higher level API than dispatch queue, it is based on objective-c, so it is ARC ready. It only supports concurrent operation, although with addDependency method, it can define the dependency between operations and make them happen sequentially. It also supports operation priority, so a new operation with high priority may run before other operation added earlier in the queue. An completion block can be used to do some work which is not part of operation task.

Dispatch queue is based on c API, it supports block for task. It supports both concurrent queue and serial queue (private dispatch queue), and Main dispatch queue. Dispatch queue does not provide method to get queued item count or cancel queued item. If it is required to cancel all queued item in serial queue, one option is adding a sync item with empty completion block, if is called, then we know all previous items have been processed.

Thursday, April 10, 2014

Client certificate authentication fails only on mac Safari browser

Safari browser on mac has a bug which causes client certificate authentication failure, although the same certificate works properly on other browsers (firefox, or chrome).  It seems the safari browser does not pick the user selected certificate to answer the server challenge if more than one client certificate is available, as it always work properly if there is one client certificate available.

To workaround the issue, in the keychain utility, move all certificates from "logon/my certificate" folder to a different folder, and only leave the one you use for client certificate authentication. Then the authentiation should work, but as long as a second client certificate is added, it will stop working. 

Monday, April 7, 2014

Encryption mode (ECB, CBC), padding, IV, salt, iteration count

For encryption mode selection, ECB mode should be avoided, the major issue with ECB is the encryption key will generate the identical ciphertext each time on the identical plaintext, so it does not hide data pattern. CBC or other encryption mode should be used if possible.

When using CBC, it uses IV (initialization vector) to alter the plaintext before encrypting with the encryption key, so it will generates a different ciphertext from the same key and plaintext. The IV is not secret, and it is required during encryption. Be sure to use a random IV each time when encrypting a blob.

As CBC works on a fixed block size, so the plaintext needs to be changed to be multiple of the block size. To do this, padding is used to append extra bytes at the end of plain text. Decryption should know what padding is used when encrypting, so the padding can be removed properly

Salt and iteration count are used to generate an encryption key from a user provided password. Salt is added to the password before it is used as encryption key. In this sense, it works in similar way as IV to break the pattern. Iteration count is how many times a encryption function should be called when convert a salted password to encryption key, its only purpose is increasing the delay for a brute fore attack. Salt and iteration count should be stored with the generated encryption key.