Friday, December 19, 2014

How to debug cordova onDeviceReady event

After loading the html page, the cordova will immediately call onDeviceReady event handle, so it is hard to set break pointer to debug the logic in onDeviceReady event.
One option is use javascript setInterval method, so it will hold the javascript until you change the bWait flag from javascript console window

The sample code looks like


  var onDeviceReady = function() {
        var originThis = this;
        var bWait = true;
        var bDone =false;
        var i = 0
        var timer = setInterval(
                function(){
                    if (bWait && i < 10 ){
                        i++;
                        console.log("set bWait to false from console window to continue");
                    }
                    else{
                        if (!bDone){
                            bDone = true;
                            clearInterval(timer);
                            yourOriginalOnDeviceReady.apply(originThis, arguments);
                        }
                    }
                }, 3000);
    }

Actually, this can also be used in other cases for attaching javascript debugger, particularly for the js script loaded into the DOM at runtime by xhr request. Just wrap the original function with the above function should do it.

Wednesday, December 10, 2014

Find ios simulator folder on mac

Option 1
1. While running the app on simulator from xcode, enter a breakpoint or just clicking the pause buttonn
2. in Xcode console window, type the below command
po NSHomeDirectory()
3. copy the path, and then from Finder, click Go->Go To Folder menu, and paste the path, it will show the simulator app bundle folder


Option 2
1. launch ios simulator, click Hardware->device->Manage Device... menu

2. in the opened xcode device screen, find the simulator item, select it, and get the identifier number

3. open Finder on mac and goto the folder of
/Users/<Your UserName>/Library/Developer/CoreSimulator/Devices

4. find the subfolder that has the same name.

5 go to data\applications folder and check the application name in each subfolder to find the you want to check

Thursday, November 20, 2014

Variables can be accessed by a javascript function

When a javascript function is called, sometime it is confusing on which variables it can access.
1. parameters passed by caller (decided at runtime)

2. local variables defined within the function,

3. closure variables
    closure variable only depends on where the function is defined, and it also includes different levels of parent scopes all the way up to the global scope.

4. global variables
   global variable is accessible in the sense of a special kind of closure variable, as all function will end up in the global scope.

5. this properties
   The properties of this object can be accessed by using this.property within a function. However, when the function is called, this object may be changed from time to time depending on how it is called. So be sure to check the property is valid before using it.

Wednesday, November 12, 2014

Get ipa file from xcode with itune

1. build the xocde project,
2. from Finder go to the product build folder to get the project's package,  for example
/Users/i826633/Library/Developer/Xcode/DerivedData/fiori-dktztqbnspcsocekrhfgynaddvhg/Build/Products/Debug-iphoneos/myproject
3. from iTune, select your device, then select App icon on top left tool bar, (it may hide in ... menu item), the app list shows and take the full window
4. select File->Add library menu, and select the project package file
5. after the app shows in the main app list window.
6. right click on the application just added, and select show in finder menu item
7. the ipa file should be in the opened Finder window

Note you can also view the content of ipa file, as the ipa file is actually a signed zipped file of the application bundle, just rename it to .zip and any zip utility is able to unzip it to a package folder.

Sunday, November 9, 2014

How to subclass NSMutableDictionary in Objective C

NSMutableDictionary (as well as other collection class) are cluster class, so they are actually abstract class, as a result, you cannot simply inherit your class from NSMutableDictionary and then just call super class' method to relay the request.

The way to do it is through a proxy object, so your derived class just creates a dummy NSMutableDictionary, but the only thing it does is to relay the caller's request to the proxy object, so you can monitor what methods are called on the NSMutableDictionaryobject, and what are the parameters are used.

The following is a sample class derived from NSMutableDictionary

@interface MyMutableDictionary : NSMutableDictionary
@end

@implementation MyMutableDictionary{
 NSMutableDictionary* _proxy;
}

- (void)removeObjectForKey:(id)aKey{
  [_proxy removeObjectForKey:aKey];
}

- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey{
  [_proxy setObject:anObject forKey:aKey];
}

- (id)objectForKey:(id)aKey{
  return [_proxy objectForKey:aKey];
}

- (NSEnumerator *)keyEnumerator{
    return [_proxy keyEnumerator];
}

- (NSUInteger) count{
    return [_proxy count];
}

- (instancetype)init {
    if (self = [super init]) {
        _proxy = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (instancetype)initWithCapacity:(NSUInteger)numItems{
    self = [super init];
    _proxy = [[NSMutableDictionary alloc] initWithCapacity:numItems];
   return self;
}

- (NSMutableDictionary *)initWithContentsOfFile:(NSString *)path{
    self = [self init];
    _proxy = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    _proxy = [[NSMutableDictionary alloc] initWithCoder:aDecoder];
    return self;
}

@end

Friday, November 7, 2014

How to reload the html page when debugging iOS/Android webview

When debugging the javascript using Safari for ios uiwebview or Chrome for android webview, sometime it needs to force to reload the html page to repeat the issues that only happens during the page loading, or to restart the page without restarting the app.

For ios, from safari's web inspector, select resource tab, and then select the root item, there is a refresh icon beside the root item, click it will reload the html page

For android, in chrome, first selecting the app from the page of
chrome://inspect/#devices
then in Chrome's Developer Tools, select Source tab, from the console window type

location.reload(true)

By doing so, any javascript breakpoints will be kept in there, and available when the html page gets reloaded.

Wednesday, November 5, 2014

Implement javascript encapsulation with closure

Javascript does not have build-in support for encapsulation, but it can realize the similar function with closure.

First, javascript cannot use scope to hide private method or variable, as local variable and function within a scope are accessible even out of scope, the following code shows this

function test() {
 
   {
  var m = "hello";
  function inner(){
alert("inner");
  }
   }

   alert(m);  //show hello
   inner(); //show inner
}


Second, object scope also does not help for encapsulation, as javascript object initializer cannot have local variables and methods, all properties and methods defined for an object are public, which cannot be used to hide internal implementation.

var Obj = {
      property1 : "my property",
      method1 : function(){
                         alert(this.property1);
                           }
     //cannot define local variable within object scope
}

Obj.method1();


So the only way to support encapsulation for javascript is by using function scope, as a function can define local variable including functions which are only visible inside the function scope. And the function can also return a set of public apis to caller to use. When caller calls the public APIs, the implementation of the Apis as inner function can access all the local variables and functions within the function scope due to the closure. Most javascript framework uses this approach to implement the encapsulation pattern in javascript. The below sample shows the basic idea of this usage.

function MyClass() {

      var privateVar = {
           property1 : "my property",
           method1 : function(){
                         alert(this.property1);
                      }
};

var privateMethod1 = function(v)
  {
  alert(v);
  privateVar.method1();
  };

var publicVariable = {
name: "John",
age: 10
};
var publicMethod = function(){
privateMethod1(privateVar.property1);
} ;
        //expose public method for caller to access
return {
publicFunc: publicMethod,
publicVar : publicVariable
};
}


function test() {
     var obj = MyClass();
     obj.publicFunc(); //call public method to access private info
     alert(obj.publicVar);
     //obj.privateMethod1(); //cannot access private member and throw exception
}

Thursday, October 23, 2014

change the size of storyboard viewcontroller to match ipad or iphone screen size

By default, the xcode will create viewcontroller in storyboard as a square, and then use constraints to adjust the actual size and control location based on actual device size. However, it may be better to show the actual iphone or ipad size when designing the screen layout.

To resize the storyboard to iphone or ipad screen size, select the storyboard item in project navigator,  then in the property file inspector, uncheck the "Use Auto Layout" and "Use Size Class", when prompting for the screen size, choose iphone or ipad

In addition, the size of view in the viewcontroller in storyboard is readonly, to adjust the view's size, select the viewcontroller item in storyboard, then in viewcontroller's size inspect, change the simulated size from fixed to FreeForm.  Then the view's size will be adjustable.

Settings that affect ios xocde 6 keychain share function

After setting the same key in Keychain Sharing ->Keychain Group in Xcode 6 project Capability setting, the two applications still failed to share the keychain item.
It turns out the below additional settings should also match:
1. in project General settings, Identity Team must be same
2. In project Build Settings, the code signing -> Code Signing identity must be same


Sunday, October 5, 2014

What is new in ios Swift comparing to Objective C

After taking a quick look at iOS swift, from my impression, it does not contain many new concept not seen in C# or Java, it is more like a catch-up to C# or java instead of a new language for developing.

Compare to Objective C, the new things swift provide are:

1. remove the compatible with c, or there is not need to prepend '@' when string is used
2. support optional types
3. support generic in class or method
4. use a single .swift file to define class instead of separate header (.h) file and (.m) implementation file
5. use tuple to return multiple values without defining the multiple output parameters


ios proper way to trust self-signed server certificate

For ios https connection, the proper way to trust self signed server certificate is to install the root CA certificate (which signs the server certificate) to device profile using MDM or iPhone configuration tool, in that way, the self-signed root certificate will be used by all ios applications on device, and it is handled transparently to the application logic.

Note, simple accept and trust the self-signed certificate on a https web page from Mobile Safari is not enough, as that will only let Safaria accepts the self-signed certificate, and does not install the certificate into device profile, so the other applications will still not trust this self-signed certificate, and fails to establish the https connection with it.

As another option, if a self signed certificate only needs to be trusted by a single application, and you have the full control of the implementation of this application, that is, the application does not use other third party library to establish https network connection, then you can also include a copy of the root certificate into the application bundle and then call SecCertificateCreateWithData and SecTrustSetAnchorCertificates to trust the self-signed certificate. Note usually you will want to trust both the build-in device root CAs and the self-signed root CA, if so, you should also call SecTrustSetAnchorCertificatesOnly with false parameter, so that both of them will be evaluated by a single call to SecTrustEvaluate.

In addition, if you handle the self-signed certificate by your application, you can get the server certificate and its root certificate information from challenge.protectionSpace.serverTrust object by calling the below code. This information can be used to prompt users to decide whether to trust this self signed certificate or not.

        SecTrustRef trust =  challenge.protectionSpace.serverTrust;
        long certCount = SecTrustGetCertificateCount(trust);
        for (int certIndex = 0; certIndex < certCount; certIndex++) {
            SecCertificateRef   thisCertificate;
            
            thisCertificate = SecTrustGetCertificateAtIndex(trust, certIndex);
            NSString* summary = (__bridge NSString *)(SecCertificateCopySubjectSummary ( thisCertificate ));
            NSLog(@"%@", summary);

            //get DER representation of the certificate data and parse it with openssl library
            CFDataRef certData = SecCertificateCopyData ( thisCertificate );
       //... parse the certificate data with OpenSSL library
       //... prompt user with the certificate information
       CFRelease(cerData);

        }

Thursday, October 2, 2014

Difference between Apple Configurator and iPhone Configuration Utility

Apple Configurator and iPhone configuration Utility provide the similar function, but are used for different purpose.

iPhone Configuration Utility is available for both Windows and Mac OS, it is mainly for developer or advanced ios user, to install or remove app, or configure the device setting. One major usage is installing self-signed server root certificate for https connection. The installed root certificate can be used by both mobile safari and client application when establishing https connection. It can also be used to install client certificate (p12) for mutual authentication, but the installed client certificate can only be used by mobile safari and is not accessible by client application.

Apple Configurator is only available for Mac OS, it provides additional function than iPhone Configuration Utility, but it is more complex to use. It is mainly for small business or organization to manage and monitor multiple devices for multiple users as an alternative to other MDM system, so that users can share the same device but keep their own data when using it. Besides the profile and configuration management, it also provides functions of backup and restore per user account, iOS version update. For developers, if you only need to use it to install a profile to a single device, you can still do from "Prepare->Settings->Profile->Install Profiles..." menu, without putting the device under Supervise control.

Both tools do not provide the function of configure the individual application through NSUserDefault change listener as regular MDM server does.




Sunday, September 28, 2014

Best resource to learn ios swift from Apple

With the release of xcode 6 and ios 8, swift is officially available for developers to create ios application. The following are some best resource from Apple to learn swift for ios programming:

Books:

Video

Friday, September 19, 2014

XCode 6 tips: storyboard zoom, ios 7 simulator, check id boolean type broken


1. In order to zoom xcode storyboard, right click on the storyboard window, and select the zoom percentage on the context menu. The shortcut key is too complex to remember.

2. As ios 7 and ios 7.1 are still used by many devices, so in addition to the ios 8 simulators installed with xcode 6, it is better to go to xcode preference->download menu to download the ios 7 and ios 7.1 simulator  for testing.

3. in ios 7,  the usual way to check whether an object is from boolean type is using
NSNumber * n = [NSNumber numberWithBool:YES]; 
if (strcmp([n objCType], @encode(BOOL)) == 0) {
    NSLog(@"this is a bool");
However the above way has broken in ios 8, the workaround is adding an additional check for the classname as below
 if (value != nil &&  [value isKindOfClass:[NSNumber class]] &&
        ( (strcmp([value objCType], @encode(BOOL)) == 0 ||

           (__bridge CFBooleanRef)value == kCFBooleanTrue || (__bridge CFBooleanRef)value == kCFBooleanFalse) ) ) {
    NSLog(@"this is a bool");

Thursday, September 18, 2014

NSUserDefault in xcode 6 ios simulator not deleted with application

After installing xcode 6, when deleting application from ios simulator, the data saved in NSUserDefault does not deleted with the application.

This is a bug in the xcode 6 simulator. To overcome this issue, either reset the simulator or call the below code in didFinishLaunchingWithOptions method

  NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
   [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
 

Tuesday, September 16, 2014

How to debug cordova javascript deviceready event

Debug cordova deviceready javascript event is not possible without making some change in cordova.js, as you cannot attach the desktop browser to the device uiwebview before the html file is loaded, but once it is loaded, the deviceready event is already fired and it is too late to attach the debugger.

In order to debug deviceready event, you can make a small change to do not call the deviceready event handler, until the debugger is attached. The following steps can be used to do so:

1.  In index.html's body element, add a button to manually fire mydeviceready event after the debugger is attached,    


<br><br><button onclick="document.dispatchEvent(new Event('mydeviceready'));">fire deviceready</button>

2. in Index.js and any other js files that listen on "deviceready" event,  change the event name from deviceready

document.addEventListener('deviceready', function 
to mydeviceready:
document.addEventListener('mydeviceready'

3. launch the app, and after attaching the desktop browser, click the "fire deviceready" button to debug device ready event handle.

It is also helpful to wrap cordova callbackFromNative function within setTimeout, so when debugging the cordova js callback, it will not hang in safari.

Sunday, September 14, 2014

how to copy and paste text from mac to ios and android

iOS simulator:

To copy text from mac to ios simulator, first select the text in mac, and then click "Command+c" to copy it.
Then on ios emulator, first click "Command+v", the string will not show up yet, you then need to select the text field and hold until the paste context menu is shown, select paste menu, the text will be pasted into the text field.



Android emulator:

The easiest way to copy text to android emulator is first selecting the text field in android emulator, and from mac terminal window, type the following command to send the string to the emulator


adb shell input text 'my text string to be copied to android emulator'

Sunday, September 7, 2014

How to add a child pane (page) in iOS setting app

The following steps can be used to to add a child pane (page) in iOS settings app for your application:
1. open settings.bundle, select the item after which you want to add the new item to open the child pane.
2. select "Editor->Add Item" menu to add a new dictionary item
3. expand the new dictionary item, change the type item to "child pane"
4. change the title item to the text you want to display
5. add a new filename item, set it to the plist file name, for example "mychildsettings"
6. open the folder of settings.bundle in Finder, then show the content of the settings bundle
7. copy setting.plist and renamed the copied file to mychildsettings.plist
8. open mychildsettings.plist in xcode and update its content to the settings you want to show in the child pane

When using NSUserDefault interface to get and set the item value defined in child pane page, there is no difference as the item defined in main settings plist file. Just need to specify the key to get and set the item value. Similarly, using registerDefault method also has no difference on the items.

The only small difference is if you need to read the default value defined in the child plist file for a item, you will need to specify the plist file name as below

NSDictionary *settingsInfo = [NSDictionary dictionaryWithContentsOfFile:[
                                                                             [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"] stringByAppendingPathComponent:@"mychildsettings.plist"]];

NSLog(@"%@", settingsInfo);

Note the key in NSUserDefault is case sensitive.

Monday, September 1, 2014

Understanding Entity Framework Code First

The feature of Code First for Entity Framework will allow developer to write code to manage data in database without first creating the table in the database. Although it is helpful in some case, it may also cause confusion if you are not sure what actually happened behind the door.

After the Entity Framework is added into the project, and the models are defined. You will need to create a dbContext class to define the dataset to expose the model as below
       [Table("Books")] // Table name
        public class Book
        {
            [Key] // Primary key
            public int BookID { get; set; }
            public string BookName { get; set; }
            public string ISBN { get; set; }
            public float price { get; set; }
        }

  public class BookDbContext :DbContext
    {
        public DbSet<Book> Books { get; set; }
        public DbSet<Review> Reviews { get; set; }
    }.

That is all required for Entity Framework to automatically create the database table with the proper schema. Note you do not need to define the connection string for the database, Visual Studio will automatically select the database based on the following rules:
  • If a local SQL Express instance is available (installed by default with Visual Studio 2010) then Code First has created the database on that instance
  • If SQL Express isn’t available then Code First will try and use LocalDb (installed by default with Visual Studio 2012)
  • The database is named after the fully qualified name of the derived context, in our case that is WebApplication1.BookDbContext

To verify this, run   command in Package Manager Console
Enable-Migrations
add-migration init
update-database

And then connecting to SQLExpress or localDB's database WebApplication1.BookDbContext, you will see the table scheme is automatically created.

At this moment, you can also update configuration seed method to create the initial data, once the code is added, just run "update-database" again will populate the record in the table.

At anytime, if you change the model class public property (scheme), you can run the below command again to update the database. Note seed method is run with the newschema update, so if you do not want to use the seed method to add the initial record again, then you will need commenting out the code in seeding method
add-migration myadditionchange
update-database


In certain cases, the database may already exist, and you only need to use code first to create the model table, if so, you will need to add a connectionstring in web.config under configuration section
<connectionStrings>
    <add name="BookContext" connectionString="Data Source=JOHN-PC\SQLEXPRESS;Initial Catalog=WebApplication1.BookDbContext;Integrated Security=True"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

The name is used by contextdb's base class constructor to find the right connection string to use.
public BlogDbContext() : base("name=BookContext") 
        { 
        } 

Note if you get anything wrong during migration, you can always use 
enable-migrations -force
to reset the migration.
 
 

Sunday, August 17, 2014

ios block, crash and retain cycle

Block is just like other objective c object, it can be retained if a variable strong refer to it.

When block is used as method argument, the block will retain or keep a strong reference to all the object variables used within the block. Usually, after the block is executed, the block will be released and then the block will also release all the variables it refers to within the block implementation.

This may cause retain cycle, if any variable referred by the block also retain the block itself. As quite ofter, the block is used as a completion handler and saved as a property for later use. The result is, the main (self) object keeps a reference to the block as a property, and the block keeps a reference to the main (or self) object automatically when the main or self object, or any of its property or instance member is used within the block. So even if all external references have been set to nil for the main object, the object by itself can keep alive as long as the property that refers to block is not set to nil.

One of the solution is using __block declaration. But it may cause other troubles. As when __block is used, block will not automatically retain the object to keep it alive, so if the object is no longer be referred in any other place, it will be release and as a result, when block is executed, the object may become nil. If the application does not handle the case, it may cause crash at runtime. Similarly, create a weak reference variable just before creating the block and then use the weak variable within the block works in the same way.

Note, when __block is not used, it only prevents the object itself to be changed within block, but data of the object, such as its properties or instance member can still be change as usual. 

Install server certificate to iOS real device using web server

Usually it requires to send an email or create mobile provision file to put a server certificate file (.cer) file into ios device for trusting https connection. But if you have a web server available, it is easier to install the server certificate from the web server.

To do so, just rename the .cer file to p12 file or convert the .cer file to .der file, and put it it a web server folder. Then access the file from web url from the device mobile safari, it will automatically prompt you to install the server certificate into device profile

The same way can also be used to install server cert to ios simulator. As with XCode 6, for ios 7/7.1 simulator, it is no longer supported to just drag and drop the certificate to simulator screen. The drag and drop still works on ios 8 simulator.

Thursday, August 14, 2014

Behavior of ios cache on NSURLConnection and UIWebView

iOS provides NSUrlCache for application to manage cache behavior, but this class is more for native connection with NSUrlConnection and NSURLSession, if the application involves UIWebView request, then using NSURLCache may not get expected behavior. As the cache behavior in UIWebView does not go through the NSUrlCache API.

To verify this, a simple testing app is created to send both xmlhttprequest in UIWebView and native NSURLConnection request, it also subclass the default NSUrlCache to get more log and control for the testing. The web server will return a response with Cache-control header of "max-age=1000", so as to be sure the cache is valid.

1. NSURLConnection request:
When sending native NSURLConnection request, response is cached for the first request, in the following requests, [NSURLCache cachedResponseForRequest] is always called to return the cached response, and the request does not go to server as expected.

If [NSURLCache RevmoeAllCachedRespones] is called, the cache will be cleared, and the next request will go to server to get response

If [NSURLCache StoreCacheResponse] is disabled to never store response, then each request will go to server, as no cache is available on client side.

2. WebView xmlhttprequest
When sending xmlhttprequest from uiWebView, response is cached for the first request, however, for the following request, the cached response will be loaded automatically without invoking [NSUrlCacah cachedResponseForRequest] method, basically, UIWebView handles the cache by itself without NSUrlCache.

If  [NSURLCache RevmoeAllCachedRespones] is called, when sending the xmlhttprequest, it can still get the cached response from somewhere without going to server.

If [NSURLCache StoreCacheResponse] is disabled to never store response, it does not affect the xmlhttpRequest for uiWebView, it can still get cached response with going to server

3. NSUrlProtocol
This behavior also affects NSUrlProtocol if it is used to cached request from UIWebView, if a xmlhttpRequest from uiWebView is already cached, then the uiWebView will directly load the cached response without invoking the canInitWithRequest method, so the NSUrlProtcol does not even get a chance to handle the request.

In addition, for requests sent from uiWebView xmlhttprequest, even if willCacheResponse method to not allow NSUrlProtocol's NSUrlConnection to store any cache, the next request can still get cached response directly without canInitWithRequest be called. Also, calling [NSURLCache RevmoeAllCachedRespones] has no effect on the cached data by xmlhttprequest, it can still load cached response successfully.

Based on the above testing, the NSURLCache API only works as expected for native NSUrlConnection function. It does not work for xmlhttpRequest sent from UIWebView.



Monday, August 11, 2014

Fix build link error when change target from ios 6.0 to ios 7.0/7.1

After converting an ios project, an link error happens related to c++ std library as shown below:

"std::basic_filebuf<char, std::char_traits<char> >::is_open() const"
"std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const"
"std::basic_ios<char, std::char_traits<char> >::widen(char) const"
"std::istream& std::istream::_M_extract<double>(double&)"

In order to fix the issue, open ios project library setting and add "libstdc++.6.0.9.dylib" to link Binary With Libraries section.

Sunday, July 27, 2014

Understanding IBOutlet and IBAction in InterfaceBuider

In XCode interface builder, when adding a UI element in storyboard, it only creates an UI element, for example UITableView or UILabel, or UIViewController, and it does not give the element reference to be accessed by external module.

However, each of these class can define property, method and IBOutlet & IBAction for external access. Actually, the IBOutlet is just a regular property, the only extra thing IBOutlet does is telling Interface Builder that this property is available to associate with other instance within the current uiViewController scope at design time, so developer can make the association easily in interface builder between IBOutlet and other elements.

So IBOutlet is only meaningful within InterfaceBuilder's UIViewController context so as to allow design time association. Similarly, the Referencing outlet shows the current UI element instance is referenced by all other instances' outlet property.

Note, you can add any object into interface builder, and they will be allocated at runtime by interface builder, and any IBOutlet can associate with those arbitrary object, even if they are nothing to do with UIView. 

Tuesday, July 22, 2014

Property, and its instance variable, accessors with ARC

Before ARC, directly access instance variables will not affect the object's references—it did not extend the lifetime of the object. If the instance variable is associated with a property, then the property should be used to access the object, so that the reference can be properly managed based on property reference attribute (strong, weak, etc).

With ARC, instance variables are strong references by default—assigning an object to an instance variable directly will extend the lifetime of the object, unless the instance variable has __weak attribute. 


By default, a readwrite property will be backed by an instance variable, which will again be synthesized automatically by the compiler. Unless you specify otherwise, the synthesized instance variable has the same name as the property, but with an underscore prefix. For a property called firstName, for example, the synthesized instance variable will be called _firstName.

By default, the property's accessor methods are synthesized automatically by the compiler.
The synthesized methods follow specific naming conventions:
  • The method used to access the value (the getter method) has the same name as the property.
    The getter method for a property called firstName will also be called firstName.
  • The method used to set the value (the setter method) starts with the word “set” and then uses the capitalized property name.
    The setter method for a property called firstName will be called setFirstName:.

Override and overload in objective C

Objective C is message based and it has the full support on override. So if a method with the same signature is implemented in both the super class and derived class, calling the method will invoke the implementation in the derived class.

The object c does not support overload, so you cannot define or implement method with the same method name and parameter name but different return types or parameter types. The reason is objective C uses selector to distinguish different method, and select only use the information of method name and parameter name, and ignore the type information, for example, NSSelectorFromString method will only take method name and parameter name as input without parameter type information.

As a result, if a class has method only methods only different from parameter types, they will be regarded as the same method. This can particularly cause problem if the two methods are defined in super and derived class separately.

Automatically select client certificate by Chrome on Mac

Two steps are required to automatically select client certificate without user interaction.
1. trust the certificate:
open keychain utility and select the client certificate, open the certificate detail by double click it. Open trust section,  in "When using this certificate" dropdown list box, select "Always trust"

2. automatically pick the certificate
create or edit file "/Library/Preferences/com.google.Chrome.plist" and insert code similar to below sample code to match the client certificate information based on the host url pattern information:

<plist version="1.0">
<dict>
  <key>AutoSelectCertificateForUrls</key>
   <array>
     <string>{"pattern":"[*.]sap.corp","filter":{"ISSUER":{"CN":"SSO_CA"}}}</string>
     <string>{"pattern":"[*.]sap.com","filter":{"ISSUER":{"CN":"SSO_CA"}}}</string>
     <string>{"pattern":"[*.]sap-ag.de","filter":{"ISSUER":{"CN":"SSO_CA"}}}</string>
   </array>
</dict>
</plist>

Friday, May 30, 2014

User gem behind proxy on MAC

1. To use gem command on mac behind proxy, set --http-proxy option
gem install --http-proxy http://corporate-proxy:1234 <gem_name>

2. To update gem
sudo gem update --http-proxy http://proxy:8080 --system 

Sunday, May 25, 2014

Create oData service provider with WCF data service with visual studio 2015

The following steps are used to create oData provider with MS WCF data service

Required software:
SQL server 2012~2014
Visual Studio 2015


1. Create Sample NorthWind database in SQL 2012
   1.1 download Northwind  database from the below link and install
http://www.microsoft.com/en-us/download/details.aspx?id=23654

   1.2 open sql server 2012, open file instnwnd.sql, replace following two lines
exec sp_dboption 'Northwind','trunc. log on chkpt.','true'
exec sp_dboption 'Northwind','select into/bulkcopy','true'
 
with the new line  
ALTER DATABASE Northwind SET RECOVERY SIMPLE
 
  1.3 execute the script and verify the northwind database is created.
 
 
2. Create Data model
  2.0 Create ASP.Net web empty project in VS2015
 
  2.1 right click the solution and select Add new Item, select Data, and ADO.Net entity Data model, named it as Northwind.edmx
  2.2 select EF Designer from Database, and choose Northwind database from SQL Server 2012
  2.3 select Entity Framework 6.x
  2.4 select the checkbox of all tables , deselect views and store procedures
 
3. Create WCF data service
  3.1 right click the solution and select manger NuGet package menu
  3.2 Right-click the project and choose Manage NuGet Packages. From the Manage NuGet Packages dialog, make sure Include Prerelease is selected in the top dropdown box. Search for “Microsoft.OData.EntityFrameworkProvider” and install it.
  3.3 Add new item from Web->WCF Data service 5.6.4, name it as Northwind.svc

  3.2 in Northwind.svc.cs, replace the comment /* TODO: put your data source class name here */ to  
System.Data.Services.Providers.EntityFrameworkDataService< NorthwindEntities >
 
 3.3 Add following lines in InitializeService method
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
          
3.4 select Northwind.svc as starting page and F5 to start the app in IE with URL of 
http://localhost:54108/Northwind.svc/Customers('ALFKI')/Orders?$filter=OrderID eq 10643
The port port 54108 may be different  
3.5 For windows8 and iis 8, you also need to enable ".NET Framework 4.5 Advanced Service" from control panel's Turn Windows Features on or off to allow query on .svc
 
4. Create client application
   4.1 create a .net form applicaton
   4.2 select "view" "Other Windows, Data Source" and select service type to add northwind service as NorthwindClient
   4.3 add a datagridview control and a button, when button is clicked, run the below code
                NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/"));
                context.IgnoreMissingProperties = true;
                var customer = context.Customers.ToList();
                dataGridView1.DataSource = customer; 
   4.4 run the app and click the button to show the customer list
   4.5 Add two textbox for user to input new customer name and id
   4.5 Add a button of "New" to create new customer with the following code
           NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/"));

            context.AddToCustomers(new Customer() { CustomerID = txtID.Text.Trim(), CompanyName = txtName.Text.Trim() });
            context.SaveChanges();
   4.6 get a id and name, click new button, the customer should be added into database
   4.7 add a button of update to update the company name with the below code
             string customerId = txtID.Text.Trim();
             NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/")); 
            var customerToChange = (from customer in context.Customers
                                    where customer.CustomerID == customerId
                                    select customer).Single();
          
            customerToChange.CompanyName = txtName.Text.Trim();
            customerToChange.ContactName = txtName.Text.Trim();

            context.UpdateObject(customerToChange);
             context.SaveChanges();
   4.8 add a button to delete a customer
     string customerId = txtID.Text.Trim();             
            NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/")); 
            var customerToChange = (from customer in context.Customers
                                    where customer.CustomerID == customerId
                                    select customer).Single();
          
           
            context.DeleteObject(customerToChange);
             context.SaveChanges();

Monday, May 19, 2014

ios setCookieAcceptPolicy not shared by apps

In apple document for NSHTTPCookieStorage setCookieAcceptPolicy,  it says "The default cookie accept policy is NSHTTPCookieAcceptPolicyAlways. Changing the cookie policy affects all currently running applications using the cookie storage.". 
The test shows that is not the case, changing the cookie policy in one app will not affect other apps running on the same device.

Friday, May 16, 2014

Warning when using NSLog to log a single NSString as NSLog(str)

When using NSLog to log a single NSString parameter, if NSLog(nstringToLog) is used, a compiler warning of "Format string is not a string literal" will show. This warning message is not very clear, and many developer will just ignore it.

However, using NSLog in this way is quite danger, and may cause your app to crash at runtime, as the string parameter to be logged may contain %, which will be parsed as format place holder,  and at runtime, NSLog method will try to cast random memory address to the type specified by %. For example:
NSString* str = @"%i %@ %@";
NSLog(str);  //output is unpredictable and also may cause crash

The properly way of using NSLog to log a single NSString should be:
NSString* str = @"%i %@ %@";
NSLog(@"%@", str)
which will correctly log the string as "%i %@ %@"


MAC fail to empty recycle/gabbage bin

The mac may fail to empty the recycle bin due to locked files in recycle bin. When it fails to empty the item in recycle bin, it will stop the empty operation and open the Finder show the recycle items.
To fix the issue:
Option 1:
1. open terminal window
2. type
chflags -R nouchg
3. drag the item from Finder's recycle bin, usually it is recovery folder at the end of the item 2's command line
4. run the command, and try again to empty recycle bin

Option 2:
right click recycle bin, once the context menu shows, press shift+option and select empty recycle bin menu. It will delete the locked files.

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.