Manbolo Blog

Manbolo Team Blog, creators of MeonArchives

Passing User Variable to xcodebuild

tweet

Building app in command line with xcodebuild can be sometimes incredibly difficult. You can use Facebook’s xctool to replace xcodebuild, but I prefer to stick with Apple’s original tools.

My last isssue with xcodebuild was to pass a custom user variable at compile time. I wanted my compilation command to be something like:

clang MyAppDelegate.m -DUSE_SETTINGS_XY=42-o MyAppDelegate.o

where USE_SETTINGS_XY is my custom settings that I can change before compilation.

Passing this custom variable from xcodebuild to the linker was really not simple. If you want to do this, just follow this how-to.

Using xcodebuild, a command line looks like:

xcodebuild \
    -project MyApp \
    -scheme MyApp \
    -sdk iphoneos6.1 \
    -configuration Release \
    build

You can then pass any custom environment variable:

xcodebuild \
    -project TestPreprocessor \
    -scheme TestPreprocessor \
    -sdk iphoneos6.1 \
    -configuration Release \
    USE_XY_SETTING=42 \
    build

But that is not sufficient for xcodebuild to translate this in a -DUSE_SETTINGS_XY=42. To do this, in your Xcode project, select your target, then ’Build Settings’ and add in the ’Preprocessor Macros’:

 USE_SETTINGS_XY=$(USE_SETTINGS_XY)

Preprocessor

You can then call xcodebuild with different values for your custom setting:

xcodebuild …  USE_XY_SETTING=3 build

or

xcodebuild …  USE_XY_SETTING=4 build

One last thing, you must give a default value to your custom setting, so your project can still be build with Xcode IDE. In your Xcode project, select your target, then ’Build Settings’ and in the right corner click on ’Add Build Setting’:

Add build setting

Select ’Add User-Defined Setting’ and USE_XY_SETTING=DEFAULT_VALUE.

Default

When you will build with the Xcode IDE, you will use DEFAULT_VALUE, and when you will build with xcodebuild, you will use the value pass in the command line argument.

From jc.

Accessibility Improvements on iOS 6

tweet

Waiting for WWDC 2013 to begin, it’s a good idea to watch the last unread sessions of last year.

Recently, I came across WWDC 2012 Accessibility for iOS session. This session is titled "Raising the bar", because making your app accessible, is not only noble, but also it’s a mark of care and polish from the developer. Accessibility on iOS is huge, and simple to implement, so there is no good reason to avoid it! (must read: Accessibility for iPhone and iPad apps and iOS Accessibility Heroes and Villains by Matt Gemmell).

iOS 6 brings some improvements to Accessibility (I wasn’t aware of it until I watch the videos). The most impressive is Speak Selection. Speak Selection lets you highlight text in any application by double tapping it. Even if you don’t have VoiceOver enabled, Speak Selection will read you the highlighted text , and will detect automatically the language used. I’ve always found that computer generated voice and speaking wasn’t good, but ’Speak Selection’ has raised the bar.

I find fascinating to have all this cleverness and power in a so small device. You can activate ’Speak Selection’ by going to ’Settings’ > ’General’ > ’Accessibility’ > ’Speak Selection’ > ’On’.

Following the reading of this session, I’ve started to watch how Accessibility is supported by my today’s apps. Interesting, my bank app from la Société Générale switches the numerical input login screen with and ’audio’ login as soon as VoiceOver has been detected. Clever and interesting (you can implement this by using UIAccessibilityIsVoiceOverRunning() and listening to UIAccessibilityVoiceOverStatusChanged notifications to find out when VoiceOver starts and stops).

App login normalApp login with VoiceOver

From jc.

Build and Deploy a Django Project on OSX from Scratch

tweet

If you read this blog, you’re certainly a front-end mobile developer (and certainly also an iOS dev). Guess what? The server part is the most important piece of your project: maybe tomorrow you will want to expand your app on Android, Windows 8, or you want a beautiful responsive HTML5 web site etc… All these frontends will speak to your back-end, and inevitably you will have to work on your backend.

Fortunately, there are tons of choice of technologies, that can really be fun to learn. At Manbolo, we have choosen to build on Django, one of the most famous Python framework.

This post is an attempt to show how to build and deploy a Django project from a new Mac, assuming you’ve nothing installed on it. The aim is to have a local developement server on our Mac, pretty similar to what can be your production server (hosted on your Linux box, or on Heroku for instance). That’s way, you can work on your server, even if your are offline. For the example, we’re going to build http://dev.mysite.com that will be powered by Django and hosted locally on your mac.

WARNING: this post describes a simple way to test a Django project in a development environnement (your local Mac). There is no security consideration, and this is not a post about how to deploy a Django app on a production server.

  1. Choices: Apache, MySQL, Python 2.7
  2. Install Xcode command line tools
  3. Install Homebrew
  4. Configure Apache
  5. Install virtualenv
  6. Create a Django project with virtualenv
  7. Deploy your Django project with mod_wsgi

1. Choices: Apache, MySQL, Python 2.7


2. Install Xcode command line tools

Let’s start. First, Xcode command line tools are needed to build MySQL and to use Homebrew.

If you already have Xcode, just go to ’Preferences… > Downloads’ then click on Command Line Tools Install button.

Xcode command line tools

If you don’t have Xcode, just go to https://developer.apple.com/downloads and search for Command Line Tools (OS X Mountain Lion) for Xcode, or Command Line Tools (OS X Lion) for Xcode depending on your OS.


3. Install Homebrew

We’ll need Homebrew to install mod_wsgi.

There are many package installers on OSX but I find Homebrew very pleasant, simple and convenient. Homebrew, originally started by Max Howell, simplify the installation of open source tools (like ImageMagick, wget, ack etc..) that are not by default on OSX.

What I really like with Homebrew is that everything is installed on a directory that is not conflicting with the system directories. By default, it’s on /usr/local but you can change to whatever you like.

Installing Homebrew is very simple; open a Terminal window and type

ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"

4. Configure Apache

First, we enable php on the local Apache with mod_php, only to use phpMyAdmin. You can manage your database by hand but franckly this is simpler with phpMyAdmin. Then we’ll enable Apache Virtual Host. This will allow us to test our Django project in our browser, at the url http://dev.mysite.com. Then, we’ll install our MySQL database, needed by Django and create a first user/database for our Django project.

Apache is installed by default on OSX Mountain Lion, open a terminal and start it:

sudo apachectl start

Go to your browser, http://localhost/, and you should see classic ’It Works’

4.1. Enable mod_php

Enable mod_php in Apache:

cd /etc/apache2
sudo vi httpd.conf

Uncomment this line:

# LoadModule php5_module libexec/apache2/libphp5.so

Make a copy of the default php.ini.default to php.ini

cd /etc/
sudo cp php.ini.default php.ini

In php.ini, change the MySQL Unix socket (MariaDB installed by Homebrew use /tmp/mysql.sock by default). If php.ini copied from php.ini.default is not writable, make it writable then replace every occurence of /var/mysql/mysql.sock with /tmp/mysql.sock (it should be at two places)

sudo chmod +w php.ini
sudo vi php.ini

Test Apache config is ok, and restart it:

apachectl configtest
sudo apachectl graceful

4.2. Enable and configure Virtual Host

We’re going to enable Virtual Host on Apache. This give you a skeletton to easily manage multiple development sites, locally on your Mac. I usually put all my document root under ~/Sites/ so we’re going to create a ~/Sites/mysite.com document root for our dev site (with our Django app, only the web site static content will be located under ~/Sites/mysite.com, our Django project will be located at ~/Documents/mysite)

cd /etc/apache2
sudo vi httpd.conf

Uncomment this line

#Include /private/etc/apache2/extra/httpd-vhosts.conf

Test Apache config is ok:

apachectl configtest

The result should be:

Warning: DocumentRoot [/usr/docs/dummy-host.example.com] does not exist
Warning: DocumentRoot [/usr/docs/dummy-host2.example.com] does not exist
Syntax OK

All is ok, we’re going to configure virtual hosts configuration files

cd /etc/apache2/extra/ 
sudo vi httpd-vhosts.conf 

Replace the content of httpd-vhosts.conf with this one. This give us a good template for future vhosts configuration file.

NameVirtualHost *:80

include /private/etc/apache2/extra/vhosts/localhost.conf
include /private/etc/apache2/extra/vhosts/dev.mysite.com.conf

For each new site you’re building, you will have a corresponding Apache configuration file. Our Django site will be under http://dev.mysite.com, so we create a virtual host on our Apache for managing this site. If you want to manage other dev site, just add as many lines as there are web sites:

include /private/etc/apache2/extra/vhosts/dev.mysite2.com.conf
include /private/etc/apache2/extra/vhosts/dev.mysite3.com.conf
include /private/etc/apache2/extra/vhosts/dev.mysite4.com.conf
include /private/etc/apache2/extra/vhosts/dev.mysite5.com.conf

Currently, we just need an Apache conf for localhost and dev.mysite.com.

Create the virtual host configuration for localhost:

sudo mkdir -p /etc/apache2/extra/vhosts/
cd /etc/apache2/extra/vhosts/
sudo vi localhost.conf 

Put this content in the localhost.conf and save it

<VirtualHost *:80>
    DocumentRoot "/Users/jc/Sites/localhost"
    ServerName localhost
    ErrorLog "/Users/jc/Sites/logs/localhost-error_log"
    CustomLog "/Users/jc/Sites/logs/localhost-access_log" common
    <Directory "/Users/jc/Sites/localhost">
            Order deny,allow
            Allow from all
    </Directory>
</VirtualHost>

Create the virtual host configuration for dev.mysite.com:

cd /etc/apache2/extra/vhosts/
sudo vi dev.mysite.com.conf 

Put this content in dev.mysite.com.conf and save it

<VirtualHost *:80>
    DocumentRoot "/Users/jc/Sites/mysite.com"
    ServerName dev.mysite.com
    ErrorLog "/Users/jc/Sites/logs/mysite.com-error_log"
    CustomLog "/Users/jc/Sites/logs/mysite.com-access_log" common
    <Directory "/Users/jc/Sites/mysite.com">
            Order deny,allow
            Allow from all
    </Directory>
</VirtualHost>

Create the log repository and document root for our virtual hosts

mkdir -p  ~/Sites/logs/
mkdir -p  ~/Sites/localhost/
mkdir -p  ~/Sites/mysite.com/

Now the test for Apache should be ok:

apachectl configtest
Syntax OK

Then, restart Apache

sudo apachectl graceful

Finally, we want to test our site in our browser locally by typing http://dev.mysite.com. To do this, we edit /etc/hosts:

sudo vi /etc/hosts

And add lines for dev.mysite.com

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost 
fe80::1%lo0 localhost
127.0.0.1   dev.mysite.com
fe80::1%lo0 dev.mysite.com

Open a terminal to check this config:

ping dev.mysite.com

And the result should be

PING dev.mysite.com (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.035 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.109 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.096 ms

Now, we you type http://dev.mysite.com in your browser, you should point to your Apache virtual host.

4.3. Install MySQL (MariaDB)

Install MySQL with Homebrew

brew install mariadb

As suggested by brew, finish the installation

unset TMPDIR
mysql_install_db --user=`whoami` --basedir="$(brew --prefix mariadb)"   --datadir=/usr/local/var/mysql --tmpdir=/tmp

Start MariaDB at login

mkdir -p ~/Library/LaunchAgents
ln -sfv /usr/local/opt/mariadb/*.plist ~/Library/LaunchAgents

Then launch it now,

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mariadb.plist

Once you’ve launch the server, set a password for the MariaDB root user:

mysqladmin -u root password ’NEW-PASSWORD’

4.4. Install phpMyAdmin

Download the last version of phpMyAdmin, unzip under

/Users/jc/Sites/localhost/phpmyadmin

In your browser type http://localhost/phpmyadmin and log with root and the password you’ve previously set.

Then go to the Users tab, and select ’Add user’

phpMyAdmin create user step 1

Create you a user with login project1 and password project1, and select ’Create database with same name and grant all privileges’ then ’Add user’:

phpMyAdmin create user step 2

That’s all, we have our database ready for our Django project.


5. Install virtualenv

virtualenv is a very powerful tool that will allow you to create a Python environment sandbox. That way, you can have multiple versions of Python with multiple modules and each environment is isolated from the others. We’re going to install virtualenv, and then install Django in a virtual environment.

Just download virtualenv-1.9.1.tar.gz in a temporary folder:

tar xvzf virtualenv-1.9.1.tar.gz
cd virtualenv-1.9.1
sudo python setup.py install

6. Creating a Django project with virtualenv

To create a virtual environment of a specific Python version, use the -p option of virtualenv and put the path of a given Python interpreter. On OSX, Python 2.7 is installed by default, so, for our Django project, we’re going to create a Python 2.7 virtual environment.

6.1. Create a Python virtual environment

  1. Create a 2.7 virtual environment with Python 2.7:

    cd ~/Documents/VirtualEnvs/
    virtualenv --python=/usr/bin/python2.7 --no-site-packages venv-python2.7-django
    
  2. Activate this virtual environment:

    cd ~/Documents/VirtualEnvs/venv-python2.7-django/
    source bin/activate
    

    Before your prompt, you should see the current virtual environment activated:

    (venv-python2.7-django) $
    

    Now, when you will launch a Python interpreter, you’ll use the interpreter installed at ~/Documents/VirtualEnvs/venv-python2.7-django/bin. When you will install any Python module with pip, you will install it only in this virtual environment and not in the system. You can deactivate the virtual environment with the command deactivate and come back to your system Python.

    Finally, to test installation:

    which python
    

    Result:

    /Users/jc/Documents/VirtualEnvs/python2.7-django/bin/python
    
  3. Install last version of Django in this virtual environment: download Django-1.5.1.tar.gz in a temporary folder (doesn’t need to be under your virtual environment, but be sure to be in a terminal where this env is activated)

    tar xzvf Django-1.5.1.tar.gz
    cd Django-1.5.1
    python setup.py install
    

    No need sudo as we are in a virtual environment now. To test it; launch python and import django

    python
    Python 2.7.2 (default, Oct 11 2012, 20:14:37) 
    [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import django
    >>> 
    

    Everything seems OK, ctrl+D to quit the interactive interpreter.

  4. Install distribute >= 0.6.28 (needed by MySQLdb). I prefer to do it manually, I don’t know why it is much slower if we relly on MySQLdb to install distribute. Download distribute-0.6.36.tar.gz in a temporary folder and

    tar xvzf distribute-0.6.36.tar.gz 
    cd distribute-0.6.36/
    python setup.py install
    
  5. Install MySQLdb in this env. Download MySQL-python-1.2.4b4.tar.gz in a temporary folder and

    tar xvzf MySQL-python-1.2.4b4.tar.gz
    cd MySQL-python-1.2.4b4
    python setup.py install
    

6.2. Create a Django project

We’re going to create our Django project. Starting from now, you should have your Python virtual environement activated (remember that our system default Python doesn’t know anything about Django). If you’re new to Django, just follow the wonderful tutorials ’Writing your first Django’ on the Django site, from part 1 to part 6. I recommand also to read the section about how to manage static files (CSS, images).

cd ~/Documents
django-admin.py startproject mysite

Edit mysite/settings.py to put the MySQL database settings

DATABASES = {
    ’default’: {
        ’ENGINE’: ’django.db.backends.mysql’, 
        ’NAME’: ’project1’,
        ’USER’: ’project1’,
        ’PASSWORD’: ’project1’,
        ’HOST’: ’’,                 # Empty for localhost
        ’PORT’: ’’,                 # Set to empty string for default.
    }
}

6.3. Test the Django project in local

In command-line, test that your Django project is working. We’re using the embedded Django server:

cd ~/Documents/mysite/
python manage.py runserver

Django local admin page


7. Deploy your Django project with mod_wsgi

7.1 Install mod_wsgi

We’re going to use Homebrew to install mod_wsgi. There is some extra step to install it, you can read https://github.com/Homebrew/homebrew-apache to have more information.

Before installation, run this command that will create a needed link for Homebrew mod_wsgi compilation:

$ [ "$(sw_vers -productVersion | sed ’s/^\(10\.[0-9]\).*/\1/’)" = "10.8" ] && bash -c "[ -d /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain ] && sudo bash -c ’cd /Applications/Xcode.app/Contents/Developer/Toolchains/ && ln -vs XcodeDefault.xctoolchain OSX10.8.xctoolchain’ || sudo bash -c ’mkdir -vp /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.8.xctoolchain/usr && cd /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.8.xctoolchain/usr && ln -vs /usr/bin’"

Then, load new Formulas into brew:

brew tap homebrew/apache

Finally install mod_wsgi

brew install mod_wsgi

Once mod_wsgi installed, we’ll enable it in Apache: edit /etc/apache2/http.conf and add this line

LoadModule wsgi_module /usr/local/Cellar/mod_wsgi/3.4/libexec/mod_wsgi.so

Test the config and restart Apache if everything is ok:

apachectl configtest
sudo apachectl restart  

7.2 Configure VirtualHost for mod_wsgi

On the one hand, all static ressources will be served by Apache and will point to /Users/jc/Sites/mysite.com/static; on the other hand, the WSGI entry-point for our Python app will be at /Users/jc/Documents/mysite/mysite/wsgi.py

We’re going to configure our virtual host configuration file for dev.mysite.com and enable mod_wsgi. Edit /etc/apache2/extra/vhosts/dev.mysite.com.conf and copy these lines:

<VirtualHost *:80>

    LogLevel info

    ServerName dev.mysite.com
    ServerAdmin jc@mysite.com

    # Static files
    DocumentRoot "/Users/jc/Sites/mysite.com"
    Alias /static/ /Users/jc/Sites/mysite.com/static/

    <Directory "/Users/jc/Sites/mysite.com/static">
        Order deny,allow
        Allow from all
    </Directory>

    # WGSI configuration
    WSGIDaemonProcess mysite.com processes=2 threads=15 display-name=%{GROUP} python-path=/Users/jc/Documents/mysite/:/Users/jc/Documents/VirtualEnvs/python2.7-django/lib/python2.7/site-packages

    WSGIProcessGroup mysite.com

    WSGIScriptAlias / /Users/jc/Documents/mysite/mysite/wsgi.py

    <Directory "/Users/jc/Documents/mysite/mysite">
        <Files wsgi.py>
            Order allow,deny
            Allow from all
        </Files>
    </Directory>

</VirtualHost>

We are using mod_wsgi in daemon mode, each Django instance will runs as a distinct user. You can get more informations on How to use Django with Apache ad mod_wsgi on the Django docs, and on official mod_wsgi documentation.

You can see that the WSGIDaemonProcess variable allows us to specify which Python interpreter we will use: by changing this path, you can specify exactly which Python virtual environment you’ll use for this Django app. Note tnat we specify the path to our Python project AND to our Python virtual environement site-packages.

I’ve not look for the right number of processes and thread one should put in WSGIDaemonProcess but 2 and 15 should be safe for our developement configuration.

Finally, put the right permissions on your local folder for Apache to acces your files:

Chmod -R 755 ~/Documents/mysite/mysite
Chmod -R 755 ~/Documents/Sites/mysite.com

Then restart Apache

sudo apachectl graceful  

7.3. Collect static files

Our static pages on your Django project will be under ~/Documents/Sites/mysite.com/static, and accessible at http://dev.mysite.com/static. Note that, with our Apache virtual host configuration, static files won’t go through the Python interpreter (there is no need to) but will be serve directly by Apache.

In your Django project, edit settings.py and change STATIC_ROOT:

STATIC_ROOT = /Users/jc/Sites/mysite.com/static/  

Then, collect all statics files from your Django project:

python manage.py collectstatic

Finally, type in your browser http://dev.mysite.com/admin and you should see:

my Django site

From jc.

Compiler Warnings for Objective-C Developers by Ole Begemann

tweet

Ole Begemann on compiler warning:

You should always strive for a project that builds with zero warnings. A code base that leaves compiler warnings unfixed is a sign of carelessness on the part of the developer.

Because the compiler knows more about machine architecture, because he is less lazy than me, because he is clever, because he is rentless, I always care when he complains.


A recent example of mine: I’ve declared an IBAction in a subclass of UITableViewCell

in GotoCell.h:

@interface GotoCell : UITableViewCell 

    - (IBAction)select:(id)sender;

@end

in GotoCell.m:

@implementation GotoCell 

    - (IBAction)select:(id)sender{
        NSLog(@"Cell has been selected")
    }

@end

In Xcode 4.6.2, these apparently innocuous lines started to give warnings:

/Users/jc/Documents/Dev/Meon/iOS-Meon/Classes/GotoCell.m:58:1: warning: attributes on method implementation and its declaration must match [-Wmismatched-method-attributes]
{
^
/Users/jc/Documents/Dev/Meon/iOS-Meon/Classes/GotoCell.h:28:1: note: method ’select:’ declared here
- (IBAction)select:(id)sender;
^
1 warning generated.

How the hell this basic Objective-C code could raise warning? Command+click on the selector name in the implementation file gives me the answer:

Warning popup

In UIResponder.h, there is a category on NSObject called UIResponderStandardEditActions, that already declared select:. The difference is just in the returned type void instead of IBAction, which are exactly the same and NS_AVAILABLE_IOS(3_0) which decorates the selector

@interface NSObject(UIResponderStandardEditActions)   // these methods are not implemented in NSObject

- (void)cut:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)copy:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)paste:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)select:(id)sender NS_AVAILABLE_IOS(3_0);

In this case, I thanks the compiler to warm me about this because I didn’t want to override the select selector of NSObject(UIResponderStandardEditActions), I just wanted to have my own selector.

So I rename my methods to selectCell:. (You can arguably say that there is a small risk that selectCell: is also declared somewhere… If only we could have namespace in Objective-C!)



Zen of Developer: always strive for 0 warning


A last note: Xcode 4.6 brings new warnings, more information at http://useyourloaf.com/blog/2013/03/03/xcode-4-dot-6-recommended-build-settings.html

From jc.

Meon on iOS: the 1,000,000 Hallmark

tweet

Meon 1,000,000

We’re proud to announce that, just today, more than 1,000,000 people have downloaded Meon on iOS.

It’s quite an achievement for a 3 person company and it’s very impressive to imagine that, at least, 1,000,000 person have seen and played to our handcrafted game.

Some recent App Store comments:

Fiendishly devious, by tokiedave - Apr 13, 2013:
Now 3.30am and my insomnia is being made bearable by playing this. Great stuff.

Very addictive, by The-Style - Apr 12, 2013:
Love it - can’t put it down, real bonus that it works on all platforms.

Very good game, by Wonthatile - Apr 12, 2013:
Add more levels…One of the best thinking games i know!!!

Nice Game, by Tarun84 - Apr 12, 2013:
Great game guys this is really first time i am writing a review for a game nice work

A fresh new idea for a puzzle app, by Simon in Leeds - Apr 12, 2013:
Great puzzle app. Works well with no problems. Very good. Can’t fault it.

Thanks to all Meon’s player!

From jc.

Launching UIAutomation Tests in Command Line

tweet

Xcode, I don’t want the iPad Simulator!

If you don’t know UIAutomation yet, I encourage you to check this very good presentation (warning: [self doPromotion]!).

While installing a Jenkins to automatically build one of the app I work on, I’ve encountered some issues trying to launch automated tests with the command line. Specifically, with the current version of Xcode (4.6.1), there is no simple way to set the Simulator device type when you’re testing/launching an Universal app. As a good iOS citizen, I’ve filled a bug report waiting for Apple to correct this. In the mean time, fortunately, there is a workaround.

Forcing the Simulator

1. Overriding TARGETED_DEVICE_FAMILY

The first step to this workaround is to force the device family of your app build. There are two solutions to do this:

I prefer the latter solution, because you don’t need to ’split’ your target and you can keep it Universal. The overriding could only be used by your Jenkins server for instance, while doing automated tests.

Let’s take an example. With Xcode 4.6.1, build your app in command line

xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
-scheme TestExample \
-sdk iphonesimulator6.1 \
-configuration Release \
SYMROOT="/Users/jc/Documents/TestExample/build" \
DSTROOT="/Users/jc/Documents/TestExample/build" \
install

Finally, install is the command to build the target and install it into the target’s installation directory in the distribution root.

Doing this, your app is build as an Universal binary. Then, if you want to lauch UIAutomation tests on it, you will use

instruments \
-t  "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate" \
"/Users/jc/Documents/TestExample/build/Applications/TestExample.app" \
-e UIASCRIPT absolute_path_to_the_test_file  

If you do this, the iPad Retina Simulator will always launch.

So to launch the UIAutomation tests with the iPhone Simulator, we can override TARGETED_DEVICE_FAMILY at build time:

xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
-scheme TestExample \
-sdk iphonesimulator6.1 \
-configuration Release \
SYMROOT="/Users/jc/Documents/TestExample/build" \
DSTROOT="/Users/jc/Documents/TestExample/build" \
TARGETED_DEVICE_FAMILY="1"
install

Where TARGETED_DEVICE_FAMILY is set to "1" for iPhone only build, and "2" for iPad only build. Then you can launch your UIAutomation tests and the right simulator will launch. A side note: you can notice that the app folder input of xcodebuild is not necessarily in the iPhone Simulator Sanbox folder (for instance, under ~/Library/Application Support/iPhone Simulator/6.1/Applications/): don’t worry, at the end of the process, the app will be installed by xcodebuild in the Simulator folder.

2. Really launching the right Simulator

But what if you want to test your app in the iPhone 3.5"" Retina Simulator and then in the iPhone 4" Retina Simulator? Forcing TARGETED_DEVICE_FAMILY will allow you basically to switch between iPhone and iPad but you won’t be able to precisely choose the device you launch.

So the second step of the workaround is to use a script by Jonathan Penn in his UI Screen Shooter project: UI Screen Shooter is a set of scripts to demonstrate how to take screen shots for iOS app for the App Store automatically using UIAutomation. One of the script Jonathan has developed is excatly what we need: choose_sim_language. With choose_sim_language, you can open the Simulator with the device you needed. For instance

choose_sim_device "iPhone (Retina 3.5-inch)"  

will launch the iPhone 3.5" Retina Simulator while

choose_sim_device "iPad"  

will launch the 1024x768 iPad Simulator.

Actual values supported by the choose_sim_device are:

Maybe in a near future we will have "iPhone 4.8-inch" ?

I encourage you to visit the UI Screen Shooter GitHub page and the post on Jonathan’s blog. His clever script is using Apple Script under the hood to select the right menu item:

#!/usr/bin/env osascript

(*
Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Chooses a device type from the iPhone Simulator using menu
selection events.

To use, make sure this file is executable, then run from the terminal:

  bin/choose_sim_device "iPad (Retina)"

Originally, I tried to do this by editing the Preference file for the
simulator, and it worked under Xcode 4.3, but now it ignores those changes
often enough that I chose to use this menu-selection route.

*)

-- START:choose.sim.device
on run argv
  set simType to item 1 of argv

  tell application "iPhone Simulator" to activate
  tell application "System Events"
    tell process "iPhone Simulator"
      tell menu bar 1
        -- Hardware menu bar item
        tell menu bar item 5
          -- Hardware menu
          tell menu 1
            -- Device menu item
            tell menu item 1
              -- Device sub menu
              tell menu 1
                click menu item simType
              end tell
            end tell
          end tell
        end tell
      end tell
    end tell
  end tell
  -- END:choose.sim.device

  -- Need to show the simulator again after changing device,
  -- or else the simulator be hidden when launched by instruments
  -- for some odd reason.
  tell application "System Events"
    set visible of process "iPhone Simulator" to true
  end tell

  -- START:choose.sim.device
end run
-- END:choose.sim.device

Wrap up

To launch UIAutomation tests with the right Simulator, with an Universal app:

  1. Build your app and overrides TARGETED_DEVICE_FAMILY

    xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
    -scheme TestExample \
    -sdk iphonesimulator6.1 \
    -configuration Release \
    SYMROOT="/Users/jc/Documents/TestExample/build" \
    DSTROOT="/Users/jc/Documents/TestExample/build" \
    TARGETED_DEVICE_FAMILY="1"
    install
    
  2. Launch the Simulator you want to test

    choose_sim_device "iPhone (Retina 3.5-inch)"
    
  3. Launch your UIAutomation tests

    instruments \
    -t  "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate" \
    "/Users/jc/Documents/TestExample/build/Applications/TestExample.app" \
    -e UIASCRIPT absolute_path_to_the_test_file  
    

From jc.

Evoland by Shiro Games

tweet

Evoland splashscreen

Really super cool project from Shiro Games: Evoland. Evoland is a RPG that aim to revisit RPG games history. The player will travel from retro 8-bit graphics to modern 3D. The game is now available on Steam for Windows and Mac, and should be available on iOS.

I love the graphics, and the pitch is terrific! Brilliant idea!

Shiro Games has been founded by Sebastien Vidal and Nicolas Cannasse. Nicolas has an impressive technical background, he has developed Haxe, an open source multi-platform programming language. Shiro Games is an independant game company based in Bordeaux: what’s cool is that Manbolo headquarter is also located in Bordeaux! Guys, if you need helps on iOS (even beta testing), we will be happy to give you a hand!

From jc.

Safari Reader Source Code

tweet

Reader javascript

I’m totally in love with Safari’s Reader feature. But sometimes, on some web article, Reader doesn’t display anything (or Reader’s button is greyed). If you’re like me, and want to see why Reader doesn’t always work properly, there is a very simple way to get Safari Reader source code.

The crazy thing is that the functionality is all Javascript based (maybe due to its grand parent Arc90 Readability project).

To see it and walk trough ReaderArticleFinder object, just do this (tested with Safari 6.0.3):

  1. Quit Safari, launch it on a blank page.
  2. Type an URL for a site that has a chance to activate Reader’s button (every blog post can work, but you can use this one if you want ) Safari 1
  3. Wait for the site to be loaded and open the WebKit Inspector ( Command ⌘ Option ⌥ I)
  4. In the WebKit Inspector window, click ONE TIME on the pause button. There is no visual feedback, I’m not sure why or if this step is necessary but just in case… Safari 2
  5. Click on the Reader button, and usually the Javascript debugger should directly step into Safari Reader source code (in Javascript!) Safari 3

Et voilà!

I’ve found the Web Inspector rather capricious so don’t hesitate to try this many times before succeded.

And if you don’t succeed, you can download it here

From jc.

MVVM Pattern on iOS by Colin Wheeler

tweet

Mind blowing article from Colin Wheeler on Model-View-ViewModel (MVVM) design pattern:

In the MVVM pattern the View Model encapsulates data/properties that the view can bind to, any validation logic and actions that can be performed. For Instance if you had a button that needs to change its title text you would have a property on the view model that the button can bind its title property to. The same goes if you need to change the color of a control or enable and disable the control. In this pattern we are essentially taking the state of our app and putting it into a view model. Its also good to note that as far as the View Model is concerned it doesn’t care where it gets this state from. It doesn’t matter if it gets it from its init method, a file on disk, Core Data, a database, etc.

Borrowed from the .Net world, I find this pattern very interesting. It’s kind of having a View Controller that is independent from the model, just tied to a View Model entity. With this pattern, the view seems more independent and swappable. You can develop your interface in an isolated way, provided you have defined your View Model. I’ll try to dig around this pattern and see how it can be transferred in the iOS world, comparing it with our venerable and beloved MVC.

And it’s the first article I’ve read that presents ReactiveCocoa in a simple way. Combined with MVVM, it can be really powerfull while simplifying your code.

From jc.

Using IB, or not Using IB

tweet

From Brent Simmons in How Much, or How Little, I Use Interface Builder These Days:

Eschewing IB does mean writing code to create and configure your views. And that is, no doubt about it, more code.

But I look at it this way: it’s fewer entities. For each line of code there would have been a corresponding thing in IB.

And fixing a thing in code is simpler than fixing it in IB — because as programmers we’re optimized for code-writing.

Want to fix a color or change the position of a view? I like doing it the way I solve every other problem: I code it.

Convinced by fellows developers (Hello Toulouse), I basically use less and less Interface Builder. If I’ve to code a very static screen, I will use Interface Builder; in all others use cases, I will do everything in code.

Pros of coding vs Interface Builder:

By the way, Brent does also a very good podcast with Michael Simmons: Identical Cousins.

From jc.

Time It! - Personal Time Tracker on Google Play

tweet

Time It! banner

We’re proud to announce our second app on Google Play, Time It!. Time It! is a clean and elegant personal time tracker: there are other time trackers but none of them were suitable for us; we just wanted someting simple and efficient. So, we did it!

We’ll be happy to have feedback on this 1.0, don’t hesitate to mail us, we’ll be happy to improve our new app!

From jc.

All Posts