Articles tagged 'development'

Page 3 of 4

Previous page

    Destroy All Software Screencasts

    I recently subscribed to Gary Bernhardt's Destroy All Software screencasts. I found these absolutely fantastic. There are only about ten to fifteen minutes each in length so it's no hassle to find the time to watch them. However they cover a lot in the short time.

    They are mostly Ruby and in particular Rails focused but the topics are applicable to any software programming. For example, I've really learned a great deal about TDD from watching this.

    The Github archive is useful, especially the Suck/Rocks Rails app. His Git config file is also really handy and I really like his log formatting. I would have liked to see him post a larger sample Rails app to Github (or for the ultimate in wishful thinking - the code for the Destroy All Software site). It would expand upon how his ideas work when confronted with the complexity and messiness of a real world system.

    Overall I highly recommend the series for any programmer regardless of what language you are using. Unfortunately I believe he's stopping soon but you get access to the entire back catalog with a subscription and they're well worth it.

    posted on February 27, 2013development


    Year Update and Reflections

    It's been a year, give or take, since I started looking into iOS development, and I wanted to write a post to reflect on where I am and what are the next steps.

    Progress on iOS to Date

    • I spent the first three months of the year learning Objective C and hacking on some small programs.

    • I spent some time experimenting with Core Data and MVC and trying to get an automated testing system up and running.

    • The summer months were quiet due to work commitments. The project I was working on switched to JavaScript which I hadn't really used before. Due to this, I spent a lot of time learning JavaScript and web frontend and backend development.

    • After the summer I came back to the app with a better understanding of MVC as implemented in iOS and Core Data and I started working on it again. I read up on TDD and started implemented tests using Cucumber and Calabash. That took me up to about October.

    • Work has stalled on it since then due to a combination of real life commitments from both family life and work. And also Skyrim! Curse you Skyrim and the hours I sank into it :)

    Current Status

    Here's where I am currently

    • App work: I didn't get as much done as I had planned at the start of last year. I got diverted in other areas, namely:

    • Testing - TDD & BDD: I hadn't planned to look at any of this but ended up spending a lot of time here and learning a great deal. Familiarizing myself with this way of programming was probably the biggest benefit I gained from the last years experimentation. I probably could have completed the app if I didn't spend so much time on TDD and tinkering with automated testing setups on Jenkins. However I wouldn't have learned anywhere near as much about proper programming techniques if I did.

    • JavaScript: I spent a good deal of time learning proper JavaScript development. The basic syntax is very similar to Java which I already knew. However I wanted to learn how to program using JavaScript correctly i.e. modular code using RequireJS, TDD using Jasmine etc.

    • Ruby and Rails: again I had not planned on researching any of this but I got interested in it while looking at JavaScript. Have done a few tutorials and would like to write a Rails app at some stage.

    I spent a lot of time over the last year becoming proficient in web app and backend development in JavaScript for a work project. I've been really enjoying this. My only previous experience of JavaScript and web development was back in college around 2000 and I wasn't too taken with it compared to Java and C development. But looking at it now and in combination with backends like Rails, I've been really impressed. I'm kind of kicking myself for tuning out on what was happening in web development over the past decade. I plan to branch out and do some posts on what I used to ramp up on this.

    On the iOS front I feel that I have a good knowledge of Objective C. However the issue is finding time to finish the app. Any time I was able to set aside a sizable chunk of time I got a lot done but getting that time is the key.

    Reflections

    I think working on this side project has made me expand my horizons more as a developer. I couldn't have predicted the areas that I would have become interested in at the start of last year. I don't think it's a coincidence that as I've started looking at more stuff outside of work, that my work projects have become more interesting. I feel like I'm able to bring so much more to a project now especially in the areas of TDD and design.

    Admittedly I haven't pursued the iOS work 100%, but I feel that the other languages I've been exposed to compensate for that. I think it was better to start out with iOS and then divert into other topics rather than not do any side work at all.

    However at the end of the day the reality is that I haven't shipped anything on iOS yet. I've been justifying this to myself by claiming all these other intangible benefits. Given what I've learned, I don't think that I've wasted my time but still I'd like to get some iOS project finished. Unfortunately given my current life and work commitments I probably won't have time to work on it over the next three months. In the meantime, I'll post about my JavaScript and TDD experiences.

    As regards the blog, looking back I am happy enough with what was posted in the past year. The main thing I'm not happy with is the regularity of the postings. The same things that have stopped me doing much software work, have also stopped me publishing much. In future I want to maintain a more regular posting rate. I aim to post at least once a fortnight and hopefully once a week.

    posted on February 23, 2013development


    Managing Sub-Modules with Git Subtree

    I've been using Git for a while now, both at work and also for my iOS projects. I'm really liking it and have nearly sorted out my workflow with it. One problem that remains for me though is how to manage external dependencies. If I need to include a library from Github for example, how do I integrate it with my source.

    The main issues that I want to solve are

    • What happens if the external library disappears? This is especially relevant for online sources like Github. Given the brittle nature of the web, I think we can take it as a given that a lot of these Github repositories will be deleted over the coming years. In this scenario I need to have a local copy of the code as a backup.

    • I should be able to update the local code with the latest or a specific tag from the external repository.

    • I want to be able to create common libraries for my own code which I can share between applications.

    • It may be that I will need to modify the code, so how do I maintain those changes. Perhaps I will need to push those changes to the external repository. This seems likely for my own common libraries.

    • I want to be able to check out all the code needed to build an application from the source control using a single checkout/clone command. This means that each application will have a full copy of all the code that is needed to build it.

    One solution that I've seen used in other projects is to use git submodule links. A git submodule points to a version of an external repository. The ones I've seen for iOS libraries will usually point to Github. When you run the git submodule init command, git will follow these links and download the source into your project.

    However in researching this, other people have reported problems using git submodules. They don't seem as simple and as usable as I would need. I'm seeing issues on sites regarding detached heads, branching, different versions etc. I just know that I will hit all these issues and probably a few more besides!

    In looking for an alternative I came across git subtrees on Wolf Rentzsch's site. This seems to fit all my needs and appears less error prone than git submodules. The code can be downloaded here and here's a good tutorial on using subtrees.

    My basic usage of it, i.e. to integrate a library from Github would be something like git subtree add --prefix=GCUtils/External/CocoaLumberjack --squash https://github.com/robbiehanson/CocoaLumberjack.git master I use the squash option to compress all the commit history of the library to just one commit message in my repository.

    One issue I ran into was adding a project which itself contained submodules. In this situation I search and find all the .gitmodules files and add those manually as subtrees in my repository.

    posted on November 5, 2012development


    Setting up Calabash on iOS

    I've been implementing some new features in iOS and in the process refactoring some existing code. As I've been making these changes, I began to feel that the code was reaching a tipping point where I was as likely to break existing features as successfully add the new functionality. In particular I was experimenting with table view controllers and there are a lot of functions to override depending on what behaviour you want. I was finding that changes for one type of behaviour were impacting functionality that I thought I had solved previously. I hadn't been doing much automated testing up to now apart from some unit testing, so I was worried about adding regression bugs.

    I decided to take a break from coding in order to implement some proper tests and specifically I wanted to do some UI testing. For this I chose the Calabash framework. This is developed by the people at Less Painful. One of them, Karl Krukow, has a detailed post comparing Calabash to the other automated frameworks out there.

    Cucumber

    Calabash is based on a Ruby test framework called Cucumber. Cucumber allows for tests to be written in high level language called Gherkin. Gherkin is written in natural language and so can be understood by anyone - not just developers. It acts as documentation as well as a test framework. I could see this as being very useful when writing an application for a client. By giving them the Cucumber tests, they can see in plain English what is being implemented and should be able to give constructive feedback. Also the tests are automated and are run from the command line.

    While learning Cucumber the two main resources I used were

    • The Cucumber website which has a number of tutorials and a great wiki.
    • The Pragmatic Programmers' Cucumber book. This is an excellent book. I highly recommend reading this before implementing any tests.

    Installation

    Cucumber requires Ruby to be installed on your system (I had previously installed it while setting up Octopress). The Calabash install process is documented on their Github page. I used the Fast Track installer using these steps.

    • gem install calabash-cucumber
    • calabash-ios setup
    • calabash-ios sim acc
    • calabash-ios gen

    This created initial test files which you can run from the command line using cucumber.

    One thing that worries me about the install process is that it creates a new scheme specifically for Calabash use. I don't really like this solution as it breaks DRY and requires keeping the original scheme and the new Calabash scheme in sync. From my experience in programming, anything that is required to be kept manually in sync, won't be. I would have preferred for the Calabash libraries to only be included in the Debug target of the main scheme or for a new target to be created on that scheme. Update: Since I wrote this post Trevor Harmon has been in touch with an alternative approach to just link in the libraries for the Debug build - more info here.

    A good blog on the Calabash install and initial test setup is here.

    First Steps with Calabash

    • I think the Calabash wiki is the best starting point for Calabash.

    • The first thing I tried was the console using calabash-ios console. I recommend this to play around and see what objects are visible to Calabash.

    • The command query("view") shows everything on screen. We can isolate specific views by filtering on the accessibility label. In some cases this wasn't useful for me. For example, I have a table where each cell has a text field. Each of these has the same accessibility label so instead I filtered using the :text property.

    • We can find out what accessibility labels are visible using label "view". Once we have a label we can do things like touching or swiping on the view or checking that the view exists using view_with_mark_exists().

    • The accessibility inspector can be used to identify the classes of UI elements and the on-screen hierarchy. Launch this from XCode under the menu item XCode->Open Developer Tool->Accessibility Inspector.

    • I found that the built-in Calabash steps were very useful to base mine on.

    • A problem I had was querying for the currently active textfield from a table of textfields. The issue was that all those textfields had the same placeholder text. To get the correct one I filtered by isUserInteractionEnabled.

    • Errors in the name of the selector passed to the backdoor command show up as connection errors.

    • Initially I struggled with writing the tests at the correct level. The temptation is to be really specific in terms of UI elements e.g. When I touch X button and swipe on Y label. However you really need to describe them at a higher level e.g. when I add a new contact, when I delete an appointment etc.

    • Initially I was unable to run a backdoor command in the before hook, which runs before each test. I had wanted to reset my Core Data database & UI at this time. The reason here is that the Calabash framework itself uses before hooks to connect to the app and I think my hook was being called before theirs. To solve this Calabash added support for defining an on_launch function which is called after the simulator has started. To implement use the following template in the hooks.rb file.

      class CallbackWorld
       include Calabash::Cucumber::Operations
       def on_launch
         # here I can call backdoor and reset the app state
       end
      end
      
      World do
       CallbackWorld.new
      end
      
    • My typical test layout is to use

      • Given to put the system in a specific state - this is where I use the backdoor function to set up the app model. I do things like erase all the Core Data objects here (from Stack Overflow) to ensure that each test starts with a clean slate.
      • When to perform an action. These are driven through the app UI.
      • Then to check the results of the actions. I've typically done these using the app UI e.g. checking for the existence of views, the state of the UI etc. As an alternative I could also use the backdoor function to check the model here.

    Issues with Calabash.

    It wasn't all smooth sailing as I did run into a few issues along the way.

    • I wasn't able to get it to integrate with my installation of Jenkins, which is unfortunate as Cucumber can output in JUnit format so it's a perfect fit for Jenkins. The problem here is on my side as lots of users on the Calabash Google Group are running Calabash from their CI system. I think it due to the jenkins user not being able to launch the iOS simulator. I need to investigate further on this.

      Update: Ru Cindrea emailed me to suggest another way of running Jenkins which may fix this problem.

      I used to launch Jenkins like this: "sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist" - which seems to be the recommended way on a lot of sites I have found.

      However, I now launch it under my own user, using "nohup java -jar /Applications/Jenkins/jenkins.war --httpPort=8080" - and everything works perfectly! I can simply use "cucumber -f junit -o results -f pretty" to start the simulator, run the tests and get my JUnit report.

    • I had found that Calabash would frequently drop the connection to the app and fail the tests as a result. Once a test run started seeing these errors for a test (Unable to make connection to Calabash Server at http://localhost:37265/) then each following test in the run would show the same error. Rerunning the tests would normally sort it out in the next run or two. Both the app and Calabash would be running fine but just couldn't seem to connect to each other. This unreliability was the most disappointing part of the tests for me.

      Update: Karl pointed me to the Google Group and I saw some updates that were needed to work with the new iOS 6 Simulator. I had seen that black screen issue as part of trying to get it working with Jenkins. So I've updated to the latest version of Calabash and on the first test run, everything worked fine. Hopefully this will resolve the issue in future.

    Initial Impressions & Next Steps

    I have to say that I'm very impressed with Calabash and indeed Cucumber in general. I think that writing these type of tests beforehand would be helpful for requirements gathering and feature design. The tests themselves are not only useful as tests but also as documentation. Unlike Word docs, we can be guaranteed that these accurately describe the current state of the system, given that they are actually run against it.

    My plans for the future

    • I need to add more tests. I initially tested this with just a single feature and that's worked out so well that I'll add this to the other features.
    • From now on, I also plan to write these type of tests for a feature before implementing it. I think that the Cucumber tests especially with the language they are written in are very effective when thinking through the behaviour of the app. They force you to describe it in high level terms rather than just diving into coding.
    • My tests currently have a lot of duplication. Once I have written a lot more of them and I gain more Ruby experience, I will look to refactor them.

    Update: After my initial post Karl Krukow emailed me with some updates on the issues I was having and I've integrated those into the blog post. He pointed out that there is a Google Group for Calabash on iOS where you can ask questions and share information.

    posted on October 22, 2012development


    Further Jenkins Setup for iOS

    Last time I went through how I set up jenkins on iOS and built a simple static library. All in all, that process went ok. The next step was to build an actual app. Unfortunately I encountered a lot more issues with this.

    The first error I got was

    Code Sign error: The identity 'iPhone Developer' doesn't match any valid certificate/private key pair in the default keychain` 
    

    This post on Stack Overflow has a really detailed set of instructions on how best to fix this. Unfortunately as my iPhone developer account is not a business one, I can't add a jenkins user to it. So to solve my problem I added my certificate to the system keychain so that now my local jenkins user can access it.

    Once that was out of the way, the next issue to rear its head was a provisioning profile error.

    Code Sign error: A valid provisioning profile matching the application's Identifier '...' could not be found
    

    I found the solution to this again on Stack Overflow. I needed to copy my provisioning profile from ~/Library/MobileDevice/Provisioning to the jenkins user's folder at /Users/Shared/Jenkins/Home/Library/MobileDevice/Provisioning Profiles.

    The next reason for the build failing was that I was invoking xcodebuild using a target instead of a scheme. The target worked fine for the static library but was failing for the app as it was unable to find all the include files. Once I switched to building a scheme, the build worked fine. Building via a scheme or target is easy to configure using the Jenkins XCode plugin. You set the XCode Schema File entry to the name of the XCode build scheme.

    Nearly there! Now that the build was working I turned my attention to getting the unit tests running. The TEST_AFTER_BUILD flag that had worked before wasn't working this time. Fortunately I found the solution on Peter Jihoon Kim's blog. I needed to create a new scheme to run my tests. Once that was done I got this error

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/Tools/RunPlatformUnitTests:95: warning: Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set).
    

    Peter's blog describes the fix for this. You need to patch the RunPlatformUnitTests file in order to remove the warning printout and invoke the tests.

    The last error I had to deal with was with the code coverage. I started seeing errors with fopen$UNIX2003 and fwrite$UNIX2003. I had seen this issue on other blogs before but hadn't encountered it myself until I tried building an app using the command line. The solution as described here is to add implementations of these into your application which simply call the standard C functions.

    #include <stdio.h>
    
    FILE *fopen$UNIX2003( const char *filename, const char *mode )
    {
        return fopen(filename, mode);
    }
    
    size_t fwrite$UNIX2003( const void *a, size_t b, size_t c, FILE *d )
    {
        return fwrite(a, b, c, d);
    }
    

    One unresolved issue was that I couldn't get clang scan plugin working for this setup. I think the issue here is that it was using targets instead of schemes. I left this one go as I didn't feel it important enough to get working. XCode runs this while I'm developing anyway. I may come back to it in future once everything else is stable.

    XCode 4.5 Updates

    So, just when I got everything working for XCode 4.4, along comes XCode 4.5. Ever since the 4.2 to 4.3 transition broke code coverage for me, I've been a bit wary of XCode updates. Sure enough after installing 4.5 and trying to build my app, I got an error message saying that the calabash framework was missing a armv7s slice ld: file is universal (2 slices) but does not contain a(n) armv7s slice: ...calabash.framework/calabash for architecture armv7s Calabash is part of an iOS testing framework based on Cucumber. I've just started to implement this form of testing and it looks really nice. Getting back to the build issue, Ash Furrow has a detailed post on this issue. We need to remove armv7s (which refers to the new A6 chip in the iPhone 5) from our valid architectures. Once Calabash gets updated to support this architecture, I can reenable it.

    Once everything built in XCode, it was time to try the jenkins build. Naturally this broke also. The problem was that the XCode plugin couldn't find the 5.1 simulator.

    xcodebuild: error: SDK "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk" cannot be located.
    

    XCode 4.5 had wiped out the simulators for 5.1 so I needed to redownload them. I was able to download these from Preferences->Downloads->Components. XCode also prompted me to download the 6.0 simulator so I got that out of the way while installing 5.1.

    Once the simulators were installed I started hitting the same RunPlatformUnitTests error as above. When I opened the script file to reinsert Peter's edits I saw that it had changed slightly. Now the error printout was happening in a function on line 80 which overrode RunTestsForApplication(). I deleted that function and I added back in the original patch at line 118 so that now it looks like

    if [ "${TEST_HOST}" != "" ]; then
        # All applications are tested the same way, by injecting a bundle.
        # The bundle needs to configure and run the tests itself somehow.
        export CFFIXED_USER_HOME="${BUILT_PRODUCTS_DIR}/UserHome/"
        mkdir -p "${CFFIXED_USER_HOME}"
        mkdir -p "${CFFIXED_USER_HOME}/Library/Caches"
        mkdir "${CFFIXED_USER_HOME}/Library/Preferences"
        mkdir "${CFFIXED_USER_HOME}/Documents"
        export OTHER_TEST_FLAGS="${OTHER_TEST_FLAGS} -RegisterForSystemEvents"
    
        RunTestsForApplication "${TEST_HOST}" "${TEST_BUNDLE_PATH}"
    else
        # If no TEST_HOST is specified, assume we're running the test bundle.
    
        RunTestsForBundle "${TEST_BUNDLE_PATH}"
    fi
    

    These changes fixed the 4.5 build issues and now I have a working build and test setup again. Finally!!

    posted on September 20, 2012development


    Setting up Jenkins on OS X

    First post in a long time. I didn't really do much iOS development over the summer and am only starting to get back into it in the past few weeks. I have some draft posts on my dealings with both Core Data and UITableViews and once those features are complete I'll post them.

    Along with coding, I've been looking at adding some build infrastructure for my projects. Having seen Jenkins used at work, I wanted to get a CI system set up for my builds here at home. I want to use it to kick off a build, run the tests and package up the iPhone app. By using something like Jenkins I can automate my build and testing process and also have a record of previous builds.

    Jenkins Install

    The first step was to install Jenkins. They provide a Mac installer - the only annoyance is that it triggers the new OS X Gatekeeper dialog blocking unsigned apps from installing. Then I loaded locahost:8080 in my browser to find that Jenkins wasn't loading and there was no error message telling me what went wrong. D'oh. The issue is that Jenkins requires Java to run but it isn't installed by default on OS X. To install simply type java into a terminal and a message box will appear prompting you to install Java.

    Then I followed the user setup from Moritz Haarmann's blog. I'm not sure if the jenkins account part is still necessary, as when I got to the stage about changing the user name in the plist file, it had already been set to Jenkins. The changing permissions on the Jenkins home folder was needed though. After that I was able to run ssh-keygen and generate some keys.

    Updating Git Workflow

    I installed the Git and XCode plugins from the Manage Jenkins screen with no issues. I then created a simple project to test it out. I just added a git clone step. This failed for me with the following errors

    Failed to connect to repository : Command "git ls-remote -h ..../MyApp.git HEAD" returned status code 128:
    stdout: 
    stderr: fatal: '..../MyApp.git' does not appear to be a git repository
    fatal: The remote end hung up unexpectedly
    

    The problem here is that the repository is on my Dropbox account (as described here). This folder is not visible to the jenkins user. I didn't want to mess around with changing permissions on the Dropbox folder so I looked for an alternative solution. A colleague at work told me about Bitbucket from Atlassian. This is similar to Github but allows for private repositories. As luck would have it, I had already been using another Atlassian product SourceTree to manage my git repositories. This tool works seamlessly with Bitbucket. Once I uploaded my ssh key to Bitbucket I could simply add another remote repository to my local repository and push to it, all from within SourceTree.

    Now that I had a repository on Bitbucket, it was time to integrate that with Jenkins. This turned out to be fairly easy. I uploaded the ssh key for the jenkins account to Bitbucket. The admin page for the repository showed its ssh address so I added a Git build step to the project using that ssh address. When the project is built now, Jenkins will download the latest code from the repository first and then continue on.

    Jenkins Issues

    While Jenkins is mostly working fine now, there were a few issues I've run into. The git checkout isn't working at all using the Git Plugin. Originally it did but then I started getting the following errors FATAL: Could not checkout null with start point 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d hudson.plugins.git.GitException: Could not checkout null with start point 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d at hudson.plugins.git.GitAPI.checkoutBranch(GitAPI.java:956) ...

    Caused by: hudson.plugins.git.GitException: Command "git checkout -f 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d" returned status code 128:
    stdout: 
    stderr: fatal: reference is not a tree: 02dbc3e456d6aa6079543eeaa8361bdebe8fac9d
    

    I wasn't able to find a solution to this so I had to stop using the Git plugin and just add an execute shell build step to clone the Bitbucket git repository. As I add more projects to Jenkins, I'll check if I get the same issues there also.

    Build XCode Project

    The XCode plugin for Jenkins made it really easy to build once setup. You add an XCode build step and configure it as necessary. I chose to do a clean build each time. The project I tested this on was a static library so I didn't need an IPA built or any of the version number updates but they should be useful when building a proper app.

    When I first tried to build I got an error saying You have not agreed to the Xcode license agreements. I needed to run sudo xcodebuild -license in the terminal to fix this.

    In order to run the unit tests, the XCode plugin recommends using two build steps, one to build the app and the other to execute the tests. The reason for this is that the test step requires extra parameters i.e. path to the simulator SDK. If you're using the OCTest framework which comes with XCode then the plugin will listen to the test output and generate JUnit compatible xml files. Jenkins can read these and add the to the build results page.

    Set up Coverage Setting up code coverage for iOS projects is not an easy task. My gcov setup for XCode 4.3 still worked for me but the problem was to integrate this with Jenkins. Coverstory would not be of use here but I found this gcovr script from the Octo Talks blog. Gcovr will convert the gcov output into a cobertura xml file which can be read by Jenkins.

    One problem I had was that for some reason, gcov wouldn't work on the files in the Jenkins workspace. I was getting gcno:cannot open graph fileerrors. Coverstory also didn't work on the files in this location. What worked for me was to copy the gcda and gcno files out to a temp folder under /Users/Shared/Jenkins/Home. Passing the original build location as the root parameter to gcovr allowed the cobertura plugin to find the source code in the html report, while also removing system headers from the coverage report. Here is the script.

    cp -r ${WORKSPACE}/build/${JOB_NAME}.build/Coverage-iphonesimulator/${JOB_NAME}.build/Objects-normal/i386/*.gc* /Users/shared/Jenkins/tmp/${JOB_NAME}
    cd /Users/shared/Jenkins/tmp/${JOB_NAME}
    gcovr -r $WORKSPACE/$JOB_NAME -x > ${WORKSPACE}/coverage.xml
    

    The Octo Talks blog also suggested a number of other metrics which could be captured in Jenkins. I added the SLOC Count and the Clang Build Scan. Both of these required installing tools and then Jenkins plugins which used those tools. This instructions on the blog covered this. Ones that I've put on the someday/maybe list are the PMD plugin and OCLint.

    At the end of all this, Jenkins is working quite well for my simple test project. Next step is to try it out on my app.

    posted on September 16, 2012development


    Localizing iOS Apps

    I was looking at a tutorial for creating a settings bundle for my app and it had separate files for different languages. I realised that I hadn't a clue how to localize iOS applications. I decided I'd better look into it now, rather than at the end of development, in case it required me to change existing code. Much better to implement with localization in mind, than retrofit at the end of development.

    I'm interested to see how many translations I'll be able to include in the app. I'm not sure how easy it will be to do the translation or even how much text there will be to translate. I'm planning a Chinese translation and for sentimental reasons I'll do an Irish translation. I'll probably try to get some European languages done also. I think that once I put in the infrastructure to do one language then adding additional ones shouldn't be too much bother.

    The basics of implementing localization is that you externalize all strings in your application to .strings files and then provide versions of these files for each language you support. The process for creating the basic localization.strings file is outlined here. In your code you can get the localized values for these strings using NSLocalizedString(@"Externalized String Name", @"").

    Localization Tools

    Using this method, we will have to deal with lots of .strings files. Xcode doesn't provide much help here so I looked around for third party apps. I bought Linguan on the Mac App Store and it looks very good. You point it at an Xcode project file and it locates all the .strings files and presents them in a nice table. It can generate text files which you can send on to your translators for them to translate and re-import their translations. I'm very pleased with it so far.

    Apart from having .strings files for strings in the code, I also need to localize the app's storyboards. Albert Mata has a fantastic tutorial on how to do this here. A big problem with localizing storyboards is that changes in one language's storyboards are not propagated to the others. Manually keeping these in sync would be a nightmare. Thankfully there is a handy script here by Ederson Machado, which will update the .strings files for the storyboard and also keep the storyboards in sync. There is a nice video outlining the features of the script here. By adding this script as a build run script, we can ensure that our storyboards are always in sync.

    Localization Workflow

    My localization workflow is as follows:

    • First I created multiple storyboards for each language using the Localization area on the sidebar. This will create a language.proj folder for each language.
    • I ran the localize.py script on the project. This generated the mainstoryboard.strings files in each of the language folders.
    • I manually add these files to Xcode. First I added the English version. Then I clicked the plus button in the Localization sidebar and added the other languages. Xcode is able to find those .strings files and link them to the overall file.
    • I create a localization.strings file to deal with the strings in the code and added all languages.
    • I ran genstrings but I don't think this is needed if you're using Linguan.
    • When I opened the project in Linguan it was able to find all the strings files, including those from the storyboard.

    I'm satisfied now that I have the localization mostly under control. One thing I still need to look at is how does this affect testing. Hopefully any test framework that I used will be able to run the tests in all languages.

    posted on May 19, 2012development


    Starting out with Core Data

    For my project, I need a way to store the model data that I will be generating. I certainly don't want to write a persistence layer for my model objects so I will definitely use a standard library for this. There are a number of options

    • Core Data. This provides an editor to create the objects and XCode will generate the required model classes for me.
    • Use a database like Sqlite directly. Core Data uses a sqlite database behind the scenes but instead I could create one directly and access it using a library like FMVH.
    • A service like Parse.com. This provides an online backend for apps.

    I don't want to use the database directly as I prefer working with objects, so that would rule out sqlite for me. Parse.com is really interesting. Among other things, it provides an online site where you can see the data in a spreadsheet interface. This tutorial shows how you can use Parse.com to implement a todo list website. It's a real pity that iCloud doesn't provide a similar API to allow non-Apple devices access the data.

    In the end I've decided to go with Core Data. The reasons for this are

    • It's an Apple standard library and one of the purposes of writing an app was to learn about iOS and Apple technologies. Where possible I've tried to stick to the Apple way of doing things as I can be sure that this approach will be supported in future - or if there is a new system, then a transition path will be provided.
    • Core Data works on the object level rather than the database level. I've programmed in objects for most of my career so this is familiar to me. I have a working knowledge of databases but I feel more comfortable using OOP.
    • I'm assuming that Core Data should integrate with iCloud better than other approaches. Thinking ahead I'd like to look at iCloud at some stage and learning Core Data first should make that a bit easier.

    Magical Record and Mogenerator

    There are some good Core Data tutorials out there. The best introduction that I found was the Stanford iOS course (lectures 13 & 14). To be honest, the code required to implement Core Data is fairly complex and verbose. To deal with that, I started looking for libraries which would improve the Core Data experience. The best I found is Magical Record. This library simplifies Core Data a great deal and provides loads of helper categories & functions. There is an excellent tutorial on MagicalRecord here. I also found this tutorial really good and it also includes a sample project which uses MagicalRecord.

    Magical Record works well with another tool called Mogenerator. You download a .dmg from the site and install from that. There is a nice tutorial here. Mogenerator generates classes from the Core Data xcdatamodel file. The normal Core Data build can also do this but the advantage of Mogenerator is that it generates a second set of classes for each Core Data entity. This second set will never be overwritten so you can write custom code in these. The first set of classes will be regenerated each time the model gets updated.

    Magical Record is available on Github. Like most iOS projects I've found there, it seems the standard way to integrate this with your project is to copy the source files into your code and work away. I'm not too comfortable with this approach and would prefer to keep third party libraries separate from my code. This would allow me to update these independently and share them between projects. I'll have to look into what options are available for this.

    posted on May 15, 2012development


    Joined the iOS Developer program

    I've been fairly busy with the Start Your Own Business course so I haven't had much time to do iOS programming. It's time to get back into it now though, and so I've just paid my subscription to the iOS developer program. I'm looking forward to being able to run code on an actual device. It's been a bit limiting working on just the simulator and there's nothing like seeing your code running on the final hardware.

    posted on April 29, 2012development


    Code Coverage Updates for Xcode 4.3

    In a previous post, I described how I got code coverage up and running in Xcode 4.2. Apple have just released Xcode 4.3 and unfortunatly updating to this has broken my code coverage. The reason is that 4.3 removes the /Developer folder and moves this internally to the Xcode.app package. While this has good consequences - it should be possible to update Xcode from the App Store like a normal app - unfortunately it has also removed the libprofile_rt library from /Developer/usr/lib. I haven't been able to find a new version of this library in Xcode 4.3. When I tried using the version from 4.2, I got "mach-o but wrong architecture" errors.

    This means that when building my unit tests with Coverage I get link errors saying that I am missing llvmgcda functions (llvmgcdastartfile, llvmgcdaincrementindirectcounter, llvmgcdaemitfunction, llvmgcdaemitarcs). I searched on Google to try and find a solution for 4.3 but it seemed all solutions were for 4.2 so I needed to try to solve this myself. The solution I came up with is fairly hacky. I'm hoping that as more people upgrade to 4.3, a better solution will be found and I can switch to that.

    My solution is to take the actual file which contained the gcda functions in libprofile_rt, add it to my own source code and compile it myself. The file in question can be found on llvm.org - here. To get it to build locally I deleted the win32 and sys includes (lines 27 to 31 inclusive) and replaced the llvm include (line 23) with #include "stdint.h". This builds fine using the Coverage build configuration and outputs the same gcda and gcno files as before. To make sure that this code doesn't end up in the released project by accident, I've included it in the unit test bundle rather than the app bundle. This is fine for me as I only need coverage when running the tests anyway.

    Update: Some feedback from Tom Black, who emailed me to point out that libprofile_rt can be found in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/ However this library did not work for either of us. Instead we got errors like The bundle “GCUtilsTests.octest” couldn’t be loaded because it is damaged or missing necessary resources. Library not loaded: @executable_path ... libprofile_rt.dylib Reason: image not found
    Also this library didn't produce .gcda files but instead generated .dia files which didn't work in Coverflow.

    What worked for Tom, but not for me, was not to include libprofile at all. This removed these errors and another incompatible binary error. Now however he got the following error. Detected an attempt to call a symbol in system libraries that is not present on the iPhone: fopen$UNIX2003 called from function llvm_gcda_start_file He found the solution to this issue here. I still got link errors when I followed this though so I need to stick with my original solution.

    Update: Another commenter Rajiv emailed me to say that creating a new target for his project made the coverage work for him. It generated the .gcda and .gcno files when he exited using exit(0). I've tried creating a new simple iOS app and I don't get any errors for this when I enable coverage.

    One thing which might explain why it still doesn't work for some of my projects is the type of project being built. My original project was a static library. I tried to create a new static library project and when I try to enable coverage I get the same link errors as above.

    posted on February 21, 2012development


    Apple's New Introduction to iOS Development

    Apple has posted a new guide to iOS development which ties together all the various strands of creating an app. (via Loop Insight). Looks really nice.

    posted on February 18, 2012development


    Adding Code Coverage to Unit Tests for Xcode 4.2

    If you are going to the effort of having unit tests, then you really need to have code coverage. This will allow you to ensure that your tests are exercising all your code. It is really easy to spot a missing test when you see a branch of an if-else with no coverage. Code coverage for me is also a way to motivate myself to implement the tests. It's like high scores in games - it gives me a target to aim for. Coverage gives feedback that your tests are actually doing something, and with each test you add, you can see the areas of untested code steadily decrease.

    To set up code coverage in Xcode 4.2 I used the guide on these blogs - Infinite Loop and Matt Rajca. Originally only the gcc compiler was supported but since then the Clang compiler has had code coverage enabled. This is important as we need to use Clang for ARC and static analysis among other things.

    XCode Build Settings

    Xcode has the concept of build configurations which can have built settings altered independently of each other. The two default configurations are Debug and Release. We want to add a new configuration named Coverage. To do this duplicate the Debug configuration.

    {% img /images/codeCoverage/NewBuildConfig.png New Build Configuration %}

    In order to specify different settings for configurations in Xcode, hover over the left hand margin directly to the left of the setting we wish to update. An arrow will appear which when clicked will expand to an additional three lines for Debug, Coverage and Release. Editing the top line will alter the setting for all versions. Altering either of the new lines will only update the setting for that version of the build.

    {% img /images/codeCoverage/BuildSettings.png Build Settings %}

    • Open the Build Settings tab for the main target. Under "Apple LLVM 3.0 compiler - Code Generation", enable both
      • "Generate Test Coverage Files"
      • "Instrument Program Flow"
    • We now need to add the libprofilert library to the build. This will link in the implementations of the coverage functions. If you are seeing link errors like "llvmgcdaincrementindirectcounter", referenced from:", then you have not done this step.
      This library is located in /Developer/usr/lib. This folder contains libprofile.a which is a static library and a libprofile.dylib which is a dynamic linked library (similar to a .dll in Windows). To link this open the Build Phases tab for the main target. Expand the "Link Binary with Libraries" and click the + button. Click "Add Other" and then find libprofile_rt.dylib in the file viewer and add it. (Note that this doesn't work for me since Xcode 4.3. I've documented the updates I needed to make here).

    Executing Tests

    Now your unit tests should run and if you examine the build output files under the DerivedData folder you should find .gcda and .gcno coverage files along with your .o files. To find this folder you can go to the Projects tab in the Organizer and select your project. The path to the Derived Data folder is listed here along with an arrow which will open the folder in the Finder.

    {% img /images/codeCoverage/DerivedData.png Derived Data %}

    From here the path to the coverage files is Build/Intermediates/${Project Target}.build/Coverage-iphonesimulator/${Project Target}.build/Objects-normal/i386. Replace ${Project Target} with the name of your project target.

    Viewing Coverage Data

    To view the coverage data I used CoverStory. Simply open the app and point it at the coverage folder. This will give a nice two pane display showing your files on the left and an editor which shows how often each line of code was hit. Now you can identify untested code and add new tests to cover them.

    posted on February 17, 2012development


Next page

Tags

By year

  1. 2020 (14)
  2. 2019 (17)
  3. 2018 (2)
  4. 2017 (11)
  5. 2016 (3)
  6. 2015 (6)
  7. 2014 (3)
  8. 2013 (11)
  9. 2012 (25)