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.