iOS 6 New Orientation Handling APIs

In iOS 6, orientation handling APIs have been dramatically changed. Previously in iOS 5, you can perhaps simply use - (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation to control how the app handles the orientation change.

- (BOOL)shouldAutorotateToInterfaceOrientation:
    (UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
            interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

However, such method has been deprecated in the newly introduced iOS 6 API, and is not be called at all anymore. Instead, - (BOOL)shouldAutorotate and - (NSUInteger)supportedInterfaceOrientations methods are now used to handle the orientation changes.

For example, to lock a certain ViewController to landscape mode, you now have to use:

// Deprecated in iOS6, still needed for iOS5 support.
- (BOOL)shouldAutorotateToInterfaceOrientation:
        (UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
            interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

// iOS6 support
- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

For more details, please refer to:

http://fostah.com/ios/2012/09/27/ios6-orientation-handling.html

Incorporate GDataXML Into Your ARC Enabled Project

GDataXML is a lightweight yet powerful XML parser created and used by Google, supporting both reading and writing XML documents and XPath queries.

If you need to include a XML parser into your Objective-C project, but don’t know which ones to choose. I suggest reading the comparison between different XML parsers and How to use GDataXML to parse XML documents to get started.

Ran into a bit trouble incoporating GDataXML into my ARC-enabled project. Just figured out how:

  1. Add GDataXML.h and .m into your project.
  2. Select the target and select Build Settings tab.
  3. Find the Search Paths -> Header Search Paths setting and add /usr/include/libxml2 to the list.
  4. Find the Linking -> Other Linker Flags section and add -lxml2 to the list (by doubling clicking the space on the right).

If you are integrating in an ARC-enabled project, there is one more step:

  1. Select Build Phases tab.
  2. Expand Compile Sources.
  3. Select GDataXMLNode.m then press Enter.
  4. On the small input box that pops out, enter -fno-objc-arc.

By now, you should have successfully incorporated GDataXML into your project and your code should be ready to go, whether or not if it’s ARC enabled.

Reference: http://ibombsite.blogspot.com/2012/02/how-to-make-gdataxmlnode-work.html and http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml

Core Data: Perform Operations In Background Threads With MagicalRecord

After spending two whole days working with Core Data, I finally found the best way (at least for me) of performing operations in background threads. Apple claimed in its documentation that “saving in a background thread is error-prone”. This is really not an exaggeration, it seems.

Through research, there seemed to be a lot of methods to implement operations in background threads, including NSNotificationCenter method, parent context method, and so many other variants. However, they either don’t work for me, or do not meet my specific needs.

Finally, I found a great wrapper class called MagicalRecord. The documentation says that performing core data operations is just as easy as this:

(Note that to use this code, you must first add MagicalRecord to your project.)

Person *person = ...;
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    Person *localPerson = [person MR_inContext:localContext];
    localPerson.firstName = @"John";
    localPerson.lastName = @"Appleseed";
}];

I thought that was the end of the headache. I was wrong.

MagicalRecord #222 works extremely well for the most part; however, it fails to save the data to local file after performing background operations. This seems to be a bug, as it should have worked fine, as claimed by the documentation.

After more searching, I finally found the solution that, once and for all, puts an end to this nightmare.

Person *person = ...;
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    Person *localPerson = [person MR_inContext:localContext];
    localPerson.firstName = @"John";
    localPerson.lastName = @"Appleseed";
} completion:^{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[NSManagedObjectContext defaultContext] save];
    }];
}];

The added code actually tells the main NSManagedObjectContext to forcefully save the data on main context after performing the operations, thus archiving our goal.

Note that by the time of this writing, such bug has not been resolved. You might find this bug already fixed when you later download the MagicalRecord.

More About Localization In iOS Development

A couple of weeks ago, I wrote an article about problems frequently encountered in iOS localization . Here I’d like to share with you more information about localization. I will talk about easy ways of localizing storyboards, .xib files and literal strings.

1. Literal Strings

Localizing literal strings is one of the basics you need to pay attention to. Moreover, if you decided to start off building a global app, you’d better localize all the literal strings ground up. This will save you from a lot of troubles and headaches.

The way to localize literal strings, as you may already know, is to use wrap a string with an NSLocalizedString marco.

Instead of writing @"Some text", you write

NSLocalizedString(@"Some text", @"Comments for translators");

You can ignore the second text parameter if you wish. The second piece of text actually serves as a comment for translators to better understand the context of your string, so that they can more accurately translate your text as desired.

After wrapping all the literal strings in this way, you can use the command tool to pull out all the strings wrapped, so that you can easily translate the text strings into multiple languages.

In order to do this,

  1. Open up Terminal.
  2. Navigate to your project folder.
  3. Create a folder called en.lproj if you haven’t already done so.
    (You will need to drag the en.lproj folder into your XCode project as well)
  4. Generate the strings file, by typing the genstrings -o en.lproj Classes/*.m command in the Terminal.

Note that Classes/*.m represents all your .m files. You should change this accordingly.

Now when you open up the en.lproj folder, you will see a new file called Localizable.strings was already generated by the Terminal command tools. The format of the file is like:

/* Comments for translators */
"Some text" = "Some text";

By now, you have extracted all the literal strings in your code. Now navigate to the Supporting Files folder (in Xcode). Click on Localizable.strings and bring up the property panel on the right. Check the languages you want to translate for. (You may need to manually create a [lang].lproj ([lang] is the code for specific languages) folder and copy the Localizable.strings into the folder, if you can’t check the languages on the right panel.)

You should see Localizable.strings of several languages appearing on the left. Just translate all the texts and paste them into the Localizable.strings of the corresponding language.

For example,

/* Comments for translators */
"Some text" = "一些文字";

In case you encounter errors like Localizable.strings error, please refer to my post before.

2. Storyboard localization

Since iOS5, Apple has been using the storyboard as the default interface builder. One way to localize the text in storyboard is to create multiple storyboards of different languages and translate the text in the storyboards respectively.

Another simpler way is to make use of the ibtool to automatically generate the strings for translation (similar to the genstrings method used above). In order to do this,

  1. Select and check the desired translation language under the Localization panel on the right. The Project navigator MainStoryboard.storyboard will be split into two different files, one for each language. (You may need to manually build different storyboad files and put them into different [lang].lproj folders.)
  2. Open up Terminal and navigate to your project folder.
  3. Navigate to en.lproj folder in Terminal. (cd en.lproj) (Make sure that the main storyboard file is in this folder. If not, navigate to the folder containing the main storyboard file.)
  4. Enter command
    ibtool --generate-strings-file MainStoryboard.strings MainStoryboard.storyboard

A file called MainStoryboard.strings will be generated. This file contains all the text to be translated in the storyboard file.

An example of the file would be like:

/* Class = "IBUILabel"; text = "First Name"; ObjectID = "CkK-0F-oZ2"; */
"CkK-0F-oZ2.text" = "Li";

/* Class = "IBUILabel"; text = "Age"; ObjectID = "M3f-at-Qtm"; */
"M3f-at-Qtm.text" = "13";

/* Class = "IBUILabel"; text = "Last Name"; ObjectID = "SMp-zG-VzS"; */
"SMp-zG-VzS.text" = "Cognom";

Now, translate all of the text into your language and save the file. That done, it’s time to execute another instruction in the Terminal window to regenerate the translated version of our storyboard, but this time with translations for all the texts. Navigate to the en.lproj folder (using Terminal) and enter the following command:

~/.../en.lproj$ ibtool --strings-file MainStoryboard.strings 
                              --write ../zh-Hans.lproj/MainStoryboard.storyboard 
                                      MainStoryboard.storyboard

Here zh-Hans.lproj should be changed to your own translation folder.

3. Seperate .xib file localization

If you are using seperate .xib files instead of the storyboard, you can also use the ibtool to generate the strings for translation. The following example shows you how to extract the English strings from the main nib of a project into a new strings file. You can store a copy of the resulting file for use later or give the file to the translation team.

ibtool --generate-strings-file MainMenu.strings en.lproj/MainMenu.nib

The following example takes the original English-based nib file and merges it with the translated strings to create a localized version of the nib:

ibtool --strings-file de.lproj/MainMenu.strings --write de.lproj/MainMenu.nib en.lproj/MainMenu.nib

Remember that translating the strings in your files is only one step of the localization process. The localizer may need to adjust the layout of views and controls to account for changes in string length. Also, ibtool does not automatically update date and time formats associated with formatter objects.

References:
http://www.albertmata.net/articles/introduction-to-internationalization-using-storyboards-on-ios-5.html
Apple Documentation

Custom Objective-C Brush For SyntaxHighlighter Evolved in WordPress

The default Objective-C brush for SyntaxHighlighter Evolved was pretty basic. After searching for great Objective-C brushes for SyntaxHighlighter in vain, I decided to create one myself. Based on the work of Matej Bukovinski and Andras Hatvani, I created this refined Objective-C brush. I actually used the exactly same colors as those used by XCode syntax highlighting. Here is one example of this brush in action.

Objective-C brush for syntaxhighlighter evolved in wordpress

To use this brush, you only need to slightly modify the default plugin. Here is a quick walkthrough.

  1. Download shBrushObjC.js and shCore.css from here.
  2. Use SSH or FTP to access your SyntaxHighlighter plugin folder (usually located at /BLOG_ROOT/wp-content/plugins/syntaxhighlighter), where BLOG_ROOT is the root folder of your blog.
  3. Copy (or replace) the file shBrushObjC.js under the folder /third-party-brushes.
  4. Access the folder /syntaxhighlighter3/styles/ (or /syntaxhighlighter2/styles/ if you are using version 2.0). Replace shCore.css with the one that you downloaded.

All set. Be sure to empty your browser cache before checking whether your codes are working all right. You can use shortcode oc or objc or obj-c to post Objective-C codes.

Feel free to contact me with any advice or questions.