How to ask and answer a technical coding question

As developers and designers, we often encounter a problem that we don’t know how to solve so we post a question to a forum or StackOverflow. Before we post the question, we need to make every attempt to solve the problem first. If we can’t solve it, we need to isolate the problem to a specific subroutine or line(s) of code by running enough tests and/or building a small test program. If we show these types of efforts when we post a question, the readers will show respect and take us seriously. They will not think we just post a random question or don’t even do some basic Googling before wasting their time.

Today, I came across an error in using UIWebView and found a StackOverflow question that is so well written that I just have to blog about. The question was answered with a perfect answer. The answer starts off with a couple references to back up the suggested solution. It goes to show the answer’s full understanding of the question and research he did to suggest the best possible answer. The answer is well presented by indicating the method in which the code should be placed and a comment in the code to indicate what needs to be done further. It then explains how the problem happens in the first place and the reasons behind it.

If every technical question is asked and answered this way, this will be a dream come true for us.

Tagged , , ,

Get Free Email Updates

If you like my blog, you can receive the latest articles in your inbox. Just enter your name and email below.



I promise I won't send you spam. You can unsubscribe at any time.

Want to subscribe by RSS? RSS Feed

A great way to do framework initialization

Framework Initialization A great way to do framework initialization

After I have developed several iOS and Mac apps, I started to realize the need to write some sharable code that can be used not just in multiple apps on the same platform (iOS or Mac), but also across platforms (iOS and Mac). I will talk about one of the best ways to do framework initialization, why and how.

Less is more

When it comes to writing any kind of library code that is meant to be reused by me or by others, I believe there should be as little framework initialization code as possible. There are 2 reasons:

  1. I will likely forget how the library works internally or its configuration options after one month or longer. If there is a lot of setup in order to use the shared code, it takes a varying degree of context switch.
  2. Others who use your code doesn’t want to know how you implement it. If they do, they would have done it themselves. They have a problem to solve and want a quick, frictionless solution to solve that problem so that they can move on to develop for their own apps.

One way of achieving this is to run your framework initialization code automatically without requiring the user of that code to initialize objects of your library that may not necessarily need to be exposed.

A Simple Loader Class

First, I like to create a new class for just this purpose. I usually name it XXXLoader because we will be using NSObject‘s load class method. Here are the header and implementation for a class named DevNewsLoader that is extracted from my DevNewsLetter project at GitHub. DevNewsLetter demonstrates how to build an universal framework that can be used for iOS and Mac apps to allow your app users to sign up for your email newsletter.

#import "DevNews.h"
#import "DevNewsLoader.h"
 
@implementation DevNewsLoader
 
+ (void)load
{
#if TARGET_OS_IPHONE
    [[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(applicationDidBecomeActive:) name:@"UIApplicationDidFinishLaunchingNotification" object:nil];
#elif !TARGET_OS_IPHONE
    [[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(applicationDidBecomeActive:) name:@"NSApplicationDidFinishLaunchingNotification" object:nil];
#endif
}
 
+ (void)applicationDidBecomeActive:(NSNotification *)notification
{
    /* Put any initialization code here like reading apiKey or listID from a property list */
 
    [DevNews devNewsWithAPIKey:apiKey listID:listID];
}
 
@end

When DevNewsLoader is loaded when the app runs, its load method is called (hence the name Loader). I use the preprocessor directives TARGET_OS_IPHONE to determine if this code is being run in an iOS or Mac app. This method simply registers DevNewsLoader as an observer of the UIApplicationDidFinishLaunchingNotification or NSApplicationDidFinishLaunchingNotification notification, depending on the platform.

When the notification is received, the applicationDidBecomeActive method is called. You can then run any framework initialization code you need for your framework/library/shared code. In DevNewsLoader‘s case, it reads the API key and list ID from a property list file and then initializes the DevNews singleton object. DevNews is now ready to be used by other developers.

One more thing

In addition to the UIApplicationDidFinishLaunchingNotification and NSApplicationDidFinishLaunchingNotification notifications, you can also observe other notifications as listed in the UIApplication Class Reference and NSApplication Class Reference. You can automatically run your framework initialization code when the app goes to the background, comes back to the foreground, or terminates.

This is a series of posts related to building frameworks for iOS and Mac. I talked in length about how to build an universal framework that you can use for both iOS and Mac apps. Are you able to use this tip to improved your shared code? I would love to hear what you think or other tips you have related to framework initialization. Just give it a shout.

Tagged , , , ,

Get Free Email Updates

If you like my blog, you can receive the latest articles in your inbox. Just enter your name and email below.



I promise I won't send you spam. You can unsubscribe at any time.

Want to subscribe by RSS? RSS Feed

Design process for DevBaseHelpers framework

Framework Design process for DevBaseHelpers framework

I will talk about how the DevBaseHelpers framework is designed and built in this post. It is used by DevBase to communicate with your target app to view the SQLite database contents during app development. You may want to read about how to build an universal framework for iOS and Mac before this post.

Many frameworks and libraries I’ve used for iOS projects require the framework user to include some header files of the framework, instantiate an object (usually a shared manager of some sort), configure the object with some parameters in a designated constructor, set some properties (including a delegate), call a method to tell the object that we are ready to start (usually in application:didFinishLaunchingWithOptions: or applicationDidBecomeActive:). Sounds familiar?

This approach consists of too many steps. It requires the framework user to understand how the framework class works and what its methods do, when the user didn’t write the class. It always leads to some documentation reading which can be fun and liberating if the documentation is well written. But sometimes it is not. The user can also misconfigure or misplace the initialization code. This results in more GitHub issues or bug reports being filed while he may just not understand how to use the framework or library. The framework maintainer also receives more support questions, and the FAQ grows.

I want DevBase and DevBaseHelpers to be easy to use for anyone. Knowing the details about the framework should not be an exercise my customers need to go through as they just want to use DevBase to help their app development.

Users do not need to know a thing about the framework

There is no header file to include, no object to instantiate, no property to set, no start method to call. I’ve taken this to the extreme that I don’t even expose any header file for DevBaseHelpers. So the framework user does not and cannot learn about the classes involved with the framework. This is deliberate.

(Almost) zero configuration

You can just link the DevBaseHelpers framework in your target app Xcode project and connect DevBase to your target app. That’s it. The defaults I choose for DevBaseHelpers work out of the box for most cases.

Configurations should belong in an external config file

DevBaseHelpers has no configuration at the code level. I’ve made the defaults work for most users for most apps most of the time. If you do require the advanced features DevBase provides, you do that in the DevBase.plist file. I’ve included a sample of how it looks when I distribute the app in the latest release. You can just copy it and then put in your own values. There is YAML for Rails; there is plist for iOS/Mac.

Plist Design process for DevBaseHelpers framework

Assure the users that it is working as intended

When you link DevBaseHelpers in your target app and run, I print out messages in the Xcode debug console to tell you what databases are available to be viewed at what port number. This is the only information you ever need to know to be sure that you have set it up correctly. You then just use DevBase to connect to the device using that port number, and you should see these same databases listed in DevBase.

Debug Design process for DevBaseHelpers framework

How well does this approach work?

Since DevBaseHelpers is built upon these design decisions, I received no support emails from customers telling me they can’t use the framework. The only framework related questions I received are the things the framework isn’t designed to do, not failed to do, in version 1.0. The new DevBase version 1.1 addresses all these questions for my customers.

If you enjoy reading this, you may also like to read about my design process for the DevBase app in my next post. DevBase uses the DevBaseHelpers framework to communicate with your target app. You can buy DevBase from the Mac App Store.

Tagged , , , , , , , , , ,

Get Free Email Updates

If you like my blog, you can receive the latest articles in your inbox. Just enter your name and email below.



I promise I won't send you spam. You can unsubscribe at any time.

Want to subscribe by RSS? RSS Feed

How to build a truly iOS universal framework for iOS and Mac with just a single codebase

iOS universal framework How to build a truly iOS universal framework for iOS and Mac with just a single codebase

If you want to share code between multiple apps for the iOS and Mac platforms or just to bundle common functionalities into an easy-to-use package, this post will show you how to create an universal framework that can be linked into any Xcode project. It makes use of kstenerud’s awesome iOS Universal Framework. My DevBase app uses this technique to build an universal framework for developers to link their Xcode projects so that you can view your SQLite database contents while developing and debugging your apps.

Install the iOS Universal Framework

First, clone the GitHub repository and install it to make these framework templates available in Xcode.

> git clone https://github.com/kstenerud/iOS-Universal-Framework.git
> cd iOS-Universal-Framework
> ./Fake\ Framework/install.sh
> ./Real\ Framework/install.sh

Create a new static framework project

The iOS Universal Framework GitHub page describes the different types of frameworks available that you can read more about, including real vs. fake frameworks, regular vs. embedded frameworks, and in what situations you may want to use them. In DevBaseHelpers’ case, we will create a real regular framework for easy distribution and without the need to distribute resources. Start a new Xcode project and select Static iOS Framework under iOS > Framework & Library.

New Project How to build a truly iOS universal framework for iOS and Mac with just a single codebase

Create a target for Mac

I built DevBase with the intention to make it work for both iOS and Mac apps. Let’s create a target for Mac too. Click on the project in the left pane to show the project settings. Click Add Target in the middle pane, select Cocoa Framework under OS X > Framework & Library. I like to add iOS and Mac suffixes to my target to distinguish them. I can do that by just clicking on the target name and rename it.

Add Mac Target How to build a truly iOS universal framework for iOS and Mac with just a single codebase

I also like to rename the schemes to reflect the two platforms. You can do so by selecting Manage Schemes and clicking and renaming.

Rename Scheme How to build a truly iOS universal framework for iOS and Mac with just a single codebase

Add your code and resources

Your Xcode project now has two targets for iOS and Mac respectively, so you have to pay attention to which target(s) you add your code and resources to. A code or resource can be used in three ways:

  • iOS only
  • Mac only
  • Both iOS and Mac

Assume we want to create a new class called Chloe. This class needs to work for both iOS and Mac. In addition, there are platform-specific functionalities related to this class. Hence, I add three classes and organize them in Xcode accordingly. I also make sure they are added to both iOS and Mac targets’ build phases correctly. Let’s add these three classes:

  • Chloe_iOS
  • Chloe_Mac
  • Chloe

I add Chloe.m to the Compile Sources build phase and Chloe.h to the Copy Headers build phase for both the iOS and Mac targets, but only added Chloe_iOS.m and Chloe_iOS.h for the iOS target, and Chloe_Mac.m and Chloe_Mac.h for the Mac target.

Add Code How to build a truly iOS universal framework for iOS and Mac with just a single codebase

Build the frameworks

Now that the framework project is set up properly for both targets, it is super easy to build them. Select the iOS target and hit ⌘-B, then select the Mac target and hit ⌘-B.

Build How to build a truly iOS universal framework for iOS and Mac with just a single codebase

Understand the frameworks

According to the GitHub page, both the device and simulator destinations for the iOS target build the same universal binary, so it doesn’t matter which you select. The Products directory shows all the frameworks it can build:

Products How to build a truly iOS universal framework for iOS and Mac with just a single codebase

For the iOS target, it also builds both a regular framework and an embedded framework. The implications are:

If your framework has only code, and no resources (like images, scripts, xibs, core data momd files, etc), you can distribute (your framework).framework to your users and it will just work.

If you have included resources in your framework, you MUST distribute (your framework).embeddedframework.

Use the framework in your app

After the frameworks are built, they are in the Products directory. You can right click on the Product in the left pane and select Show in Finder. To use it in your target app, you just drag the framework from the Finder to your app’s project.

If you need to expose your framework’s header files for your target app to use, you first need to move them from the Project section to the Public section of the Copy Headers build phase. For example, if I want my app to be able to use the Chloe class, I need to expose it as follow:

Header How to build a truly iOS universal framework for iOS and Mac with just a single codebase

To include the header file, you just import it like so:

#import <Chloe iOS/Chloe.h>

And then add the -ObjC flag to Other Linker Flags in your app’s build settings.

Other Linker Flags How to build a truly iOS universal framework for iOS and Mac with just a single codebase

Your app should now be able to instantiate an object of class Chloe and call its instance methods.

One more thing…

After you update Xcode to a new version, you need to reinstall the iOS Universal Framework for projects that use it to compile. This is as simple as uninstalling and installing the templates again:

> cd iOS-Universal-Framework
> ./Fake\ Framework/uninstall.sh
> ./Real\ Framework/uninstall.sh
> ./Fake\ Framework/install.sh
> ./Real\ Framework/install.sh

Restart Xcode and compile your project.

I just showed you how you can build an universal iOS framework to share code between your iOS and Mac apps. This same technique is used to build the DevBaseHelpers framework for DevBase. I will talk more about the design process for DevBase in my next post.

Tagged , , , , , , , , , ,

Get Free Email Updates

If you like my blog, you can receive the latest articles in your inbox. Just enter your name and email below.



I promise I won't send you spam. You can unsubscribe at any time.

Want to subscribe by RSS? RSS Feed

DevBase has three new awesome features

Database DevBase has three new awesome features

Since I released DevBase in the Mac App Store, I have received a lot of positive feedback from my customers about how DevBase has helped them increase their productivity when developing for the Apple platforms. They also mentioned features they would like to see. I am very happy to tell you that DevBase has three new awesome features.

Custom port

DevBase runs on its own port of 12345 to communicate with your target app. You can now specify a custom port for DevBase by appending :<port> to the IP address as in 192.168.1.2:88888. Yes, it is just like a URL. This is useful if your target app already uses 12345 for something else. It also helps if you run DevBase and your device on different subnets controlled by routers that block certain ports.

Custom Port DevBase has three new awesome features

Specify database location

Most apps use Core Data with Xcode’s default location for the underlying SQLite database file which works fantastically. DevBase takes advantage of this to avoid requiring the user to configure anything, so it just works out of the box. However, other apps store the database file in a different location in the filesystem, so DevBase needs to look elsewhere for the SQLite database file. With the latest version of DevBase, you can now specify where your database is located. You can also rename your database file to AngryBirdLovesToCutTheRopeToMakeTheFruitNinjaFall.sqlite. How wonderful!

Now you may ask – what if your app uses more than one database. This leads us to …

Multiple databases support

Multiple Databases DevBase has three new awesome features

Some of my users have really heavy database usage for their apps. Although I haven’t needed more than one database in any of my apps, my customers certainly have. It is quite easy to tweak DevBase to support this. So why not?

You can now specify all your databases in an array in a plist file. All of them show up in DevBase once you connect to your app. Connect once, see everything. Other tools require you to download and open multiple database files to view their contents. DevBase makes this easy and fast.

Multiple Databases1 DevBase has three new awesome features

The Plist

All these features come bundled in a single DevBase.plist file of which you can find a sample from the bundled DevBase.zip file. It looks like:

Plist DevBase has three new awesome features

One thing to note is that the database paths need to be absolute paths. You can find these paths easily:

For an iOS app:

    NSString *productName = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleName"];
    NSString *databaseName = [NSString stringWithFormat:@"%@.sqlite", productName];
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *databasePath = [documentPath stringByAppendingPathComponent:databaseName];
    NSLog(@"%@", databasePath);

For a Mac app:

    NSString *productName = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleName"];
    NSString *databaseName = [NSString stringWithFormat:@"%@.sqlite", productName];
    NSString *applicationSupportPath = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
    NSString *bundleIdentifier = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleIdentifier"];
    NSString *databasePath = [[applicationSupportPath stringByAppendingPathComponent:bundleIdentifier] stringByAppendingPathComponent:databaseName];
    NSLog(@"%@", databasePath);

To ensure DevBase is set up correctly for your target app, you can watch the debug console output something like the following:

Debug DevBase has three new awesome features

You can buy DevBase in the Mac App Store today. In future posts, I will talk about how I came about to develop DevBase, and the design decisions I made. I will also talk about how you can build iOS universal frameworks such as DevBaseHelpers to share code and bundle common functionalities for your apps too. You can sign up below to be notified when they become available.


Want to learn more about building frameworks for iOS and Mac apps?



Tagged , , , , , , , , , ,

Get Free Email Updates

If you like my blog, you can receive the latest articles in your inbox. Just enter your name and email below.



I promise I won't send you spam. You can unsubscribe at any time.

Want to subscribe by RSS? RSS Feed