Categories
Blog Code

Logging in Swift

Here is my poor man version of logging for SWIFT

func logPrint(logMessage: Any, _ file: String = __FILE__, _ function: String = __FUNCTION__, line: Int = __LINE__) {
    print("\(file):\(line):0: \(function): \(logMessage)")
}

This method besides printing your message it shows the file name, the line and the function method where the log was made. The file, function and line numbers are extracted using literal expressions.

This makes it easier to find where the log message come from and if you have the KZLinkedConsole plugin installed in Xcode you just need to click on the error message in the console and Xcode will take you there.

For a more advanced logging library I recommend XCGLogger

== Update (2016-01-25) ==

I found out that the print statement doesn’t print to the System Logs, this could be useful in scenarios that you want to see the log message on a user device. So I update my method to use the NSLog function

func logPrint(logMessage: Any, _ file: String = __FILE__, _ function: String = __FUNCTION__, line: Int = __LINE__) {
    NSLog("\(file):\(line):0: \(function): \(logMessage)")
}
Categories
Blog Code

DVR

I really like DVR approach to networking testing. So much better than mocking.

 

Categories
Blog

Crash Tools Metrics

A nice site provided by HockeyApp to compare all the features of crash analytics tools.

http://www.crashprobe.com/ios/

Categories
Portfolio

Charles Stanley Mobile App

cs

Role: Lead Architect for the mobile projects  and Lead Developer for the iOS app.
Client: Charles Stanley
Links: Apple App Store

The Charles Stanley Direct mobile APP is the company’s first foray into smart applications and delivers news, features and research from the country’s leading direct-to-consumer investment platform. Charles Stanley Direct is an award-winning and innovative digital service backed by one of the country’s longest established investment management companies (Charles Stanley Group PLC) who can trace its origins back to 1792 and whose name first appeared on the London Stock Exchange in 1852. Always a leader and innovator, Charles Stanley Direct is the digital and mobile-ready arm of this £20 billion business and continually tops comparison tables in the UK against the leading D2C platforms. Recently the company was voted as “leading Innovation in Consumer Platforms” at the Aberdeen UK Platform Awards 2015 and was also named by Boring Money as the “best for ISA accounts at £10,000”. Charles Stanley Direct continues to deliver outstanding personal service to its digital D2C clients and challenges the longer established players with continual upgrades, pricing models and products.

Categories
Blog

Create an IPA using xCodeBuild

Xcode 5 brought a lot of improvements to the xCodeBuild command line tool. The most acclaimed by the developer community was that you finally can run your unit tests trough the command line using the Test build action.

Beside the Test action there was another big improvement: the new -exportArchive option. This new option allows to export archive to IPAs trough the command line and signed them with a designated profile. No more need of the xcrun PackageApplication.

Where before you did something like this:

xcrun -log -sdk iphoneos PackageApplication "$OUTPUTDIR/$APPNAME.app" -o "$OUTPUTDIR/$APPNAME.ipa" -sign "$DEVELOPER_NAME" -embed "$PROVISIONING_PROFILE"

You can now do this:

# First build the archive
xcodebuild archive -scheme $SCHEME_NAME -archivePath $ARCHIVE_NAME
# Then export it to an IPA
xcodebuild -exportArchive -archivePath $ARCHIVE_NAME.xcarchive -exportPath $ARCHIVE_NAME -exportFormat ipa -exportProvisioningProfile "$PROVISIONING_PROFILE" -exportSigningIdentity "$DEVELOPER_NAME"

The syntax is very similar to the PackageApplication command, you just need to create your archive first then export it to the IPA format. For Mac developers out there you can also export to the APP or PKG format.

Categories
Blog

A better UIAppDelegate

One of the most common ugly patterns I see while reviewing iOS code is the overcrowding of the UIAppDelegate with calls for all kinds of services. It all starts with the CoreData stack setup code, then someone adds code to setup an analytics service, short followed by a Push Notification service, InApp Purchase, Crash Reporter, etc…

Before you notice it the AppDelegate gets hundreds of lines of unrelated code, hard to maintain and gets to be a central point of all dependencies. One simple pattern can help us to break this cycle: Delegation.

For each of the services create a controller class that represents that functionality and then delegate the necessary calls from the UIApplicationDelegate to the controller. Let’s see an example with the CoreData code.

Start by creating a Master-Detail Application projet using the XCode and select the CoreData option. You will get an AppDelegate with the following properties and methods:

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;

@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;

Why do we need these methods to be were? We can be easily be moved them to a singleton class called DataController and then refer to it instead implementing them in the AppDelegate. The interface of this object can look like this:

@interface SEDataController : NSObject

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

+ (SEDataController *)sharedInstance;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

But this will only solve part of the issue, we still have calls being made on the AppDelegate to the singleton. Instead of flooding the AppDelegate with calls on each delegate method we can make our controllers implement UIApplicationDelegate protocol.

@interface SVEDataController : NSObject 

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

+ (SVEDataController *)sharedInstance;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;</pre>
and then on the .m file we implement the UIApplicationDelegate methods that make sense for this service:
<pre>#pragma mark - UIApplicationDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self managedObjectContext];
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    [self saveContext];
}

For this methods to work you need to refactor your AppDelegate in a way that it forwards the calls to available services

- (NSArray *) services {
    static NSArray * _services;
    static dispatch_once_t _onceTokenServices;
    dispatch_once(&amp;_onceTokenServices, ^{
        _services = @[[SVEDataController sharedInstance]];
    });
    return _services;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    id service;
    for(service in self.services){
        if ([service respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]){
            [service application:application didFinishLaunchingWithOptions:launchOptions];
        }
    }
}

As you can see we know have a service array that holds all of our services. These services can them respond to the UIApplicationDelegate selectors that are relevant for their execution.

You can now easily add more services, for more services  check the example project for SVEApplicationDelegate in github.

Categories
Blog

Styling your app

One of the great challenges in iOS development is how to do the styling if your app in a easy maintainable way.
A lot of people start by doing it in their nib or storyboards directly, but they quickly find the limitations: no way to set custom fonts in your components, no way to refer any kind of global variables for things like background color or image, standard offsets etc…

My favourite approach at the moment is to set all these values by code on viewDidLoad methods using the help of category methods on UIFont, UIColor, UIImage, UIFont and others.

To help in more tricky styling I sometimes use the Paint Code App (Apple should copy some  of the ideas here to their IB editor)

Recently I found a very powerful alternative: Pixate. This tools is a iOS framework that allows you to style your interface using CSS files. It even allows download and applying of style files while the application is running! I’m seriously considering giving it a go it for my next project.

Categories
Blog

YouTube Videos

Until recently to display YouTube videos in iOS or Android you need to use or an external player or some kind of Web view. The first approach made users leave your app and the second one normally was slow and buggy.

Recently Google finally launched an YouTube Player API for Android.

Unfortunately there isn’t a version for iOS but some nice fellows developed LBYouTubeView. This component is a MPMediaPlayerController subclass that is capable of displaying YouTube videos URL. It manages this by requesting information of the video from YouTube and then getting an URL to the media stream that can be played using a MPMediaPlayerController. Not sure if it’s 100% reliable and legal but it does the job!

Categories
Blog

Link to your App

Do you ever struggle to do a proper link to your application on the Application Stores? Where do I get that brand logo? Is it the right size? What’s the link to my app?

Say hello to the link makers kindly provided by Apple and Google:

And after you have done this you can go the extra level by adding this metadata to your app website.

Categories
Blog

MOGenerator integration in XCode

MOGenerator is a command line utility that generates NSManagedObject class files based on you model files. It creates a NSManagedObject derived class for each entity of your model.
The utility can be run manually every time you change your model files (.xcdatamodeld).
This manual process can easily be forgotten, and ideally we want it to automatic regenerate the files every time you change the model.
We can use XCode Build Rules to add an extra step on the processing of model files. So every time you change them XCode itself will run MOGenerator and generate new files.
To do this follow this steps:

  • Create a folder inside your project called MOGenerator and copy the mogenerator binary file inside. I normally place it inside a folder called Libraries/MOGenerator inside the project. If you are a GIT user you can setup it as a git submodule in your project .
  • Open the Project settings view, select your target, open the Build Rules tab.
  • Add two new build rules, one for “Data model files” and another for “Data model version files” this is done be selecting the Process dropdown.
  • Change the Using dropdown to Custom Script
  • Add the following code to the script text box.  (Here is a list of all XCode environment variables).
  • For Data model files:
mogenerator --model "${INPUT_FILE_PATH}" --output-dir "${PROJECT_DIR}/XXXXX/Source/Model" --template-var  arc=true
${DEVELOPER_BIN_DIR}/momc -XD_MOMC_TARGET_VERSION=10.7 "${INPUT_FILE_PATH}" "${TARGET_BUILD_DIR}/${EXECUTABLE_FOLDER_PATH}/${INPUT_FILE_BASE}.mom"
  • For Data model version Files:
mogenerator --model "${INPUT_FILE_PATH}" --output-dir "${PROJECT_DIR}/XXXXX/Source/Model" --template-var  arc=true
${DEVELOPER_BIN_DIR}/momc -XD_MOMC_TARGET_VERSION=10.7 "${INPUT_FILE_PATH}" "${TARGET_BUILD_DIR}/${EXECUTABLE_FOLDER_PATH}/${INPUT_FILE_BASE}.momd"
  • Change the output-dir parameter to your specific generation path. This is the path where mogenerator will save the files.
  • Set the Output Files to the following values:
  • Data model Files:
$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).mom
  • Data Model Version Files:
$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).momd
  • Next step is to enter the name of the Class for your entity. Entity name and Class have to be the same
  • Build the project and check if you don’t get any failures in the build process.
  • Any entities which are new (that is, which MOGenerator has not encountered in a previous build) will need to be manually added to your project. This step only needs to be performed when you have new entities, not during updates to existing entities.
  • If you have multiple targets in your project which utilize your data model, you’ll need to add these build steps for each target to make sure the model is kept up to date for each target. If this is the case you could consider to move the script commands to an external script file and refer to it on the shell script in XCode.