Brian Coleman

  • Home
  • ABOUT
  • SERVICES
  • PORTFOLIO
  • BLOG
  • Contact

Tutorials 45

Tutorial: Threads

Threads allows you to execute multiple code paths concurrently within your application. The reason you’ll use it is to speed up the performance of your application by running some code on another thread while other operations are happening on the main thread. This is helpful for when you need to pre-load data. I’ve used this before in a magazine app where I needed to pre-load the next couple of pages while the user is reading the current page, this made the application much smoother when swiping to the next page.

There are a couple of disadvantages to threads, one problem with creating threads yourself is that they add uncertainty to your code. Threads are a relatively low-level and complicated way to support concurrency in your application. If you do not fully understand the implications of your design choices, you could easily encounter synchronization or timing issues, the severity of which can range from subtle behavioral changes to the crashing of your application and the corruption of the user’s data. Another problem area with Cocoa and multithreading comes from user interface updates. All UI updates in Cocoa must be done on the main thread, or instability can result. If you have a background thread performing a calculation, make sure to wrap whatever method updates the UI in a -performSelectorOnMainThread:withObject:waitUntilDone: method call. The single biggest source of crashes with multithreaded Cocoa applications is simultaneous access to a shared resource.

Grand Central Dispatch (GCD)

Grand Central Dispatch is one of the most common ways to add threads. With GCD, you define the task you want to perform and add it to a work queue, which handles the scheduling of your task on an appropriate thread. Work queues take into account the number of available cores and the current load to execute your tasks more efficiently than you could do yourself using threads.

Adding a Task to a Queue

dispatch_async(myQueue, ^{
    // Insert code to be executed on another thread here
    [self methodName];
});
dispatch_release(myQueue);

To execute a task, you must dispatch it to an appropriate dispatch queue. You can dispatch tasks synchronously or asynchronously. Once in a queue, the queue becomes responsible for executing your tasks as soon as possible, given its constraints and the existing tasks already in the queue. Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue. If you need to dispatch to the current queue, do so asynchronously using the dispatch_async function.

Performing Tasks on the Main Thread

You can use to execute tasks on your application’s main thread while you’re running code on another thread. You can get the dispatch queue for your application’s main thread by calling the dispatch_get_main_queue function. Tasks added to this queue are performed serially on the main thread itself. Therefore, you can use this queue as a synchronization point for work being done in other parts of your application.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    // Insert code to be executed on another thread here
    [self methodName];
    dispatch_async(dispatch_get_main_queue(), ^{
        // Insert code to be executed on the main thread here
        [self methodName];
    });
});
dispatch_release(queue);

Suspending and Resuming Queues

It’s not possible to stop a queue after it has been called because it would cause your application to be unstable but you can pause and resume the queue. You suspend a dispatch queue using the dispatch_suspend function and resume it using the dispatch_resume function.

-(void) startRunning {
    // queue will need to be defined in your header since it's use globally in the class
    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        // Insert code to be executed on another thread here
        [self methodName];
    });
}

-(void) userCancels {
    if (queue) {
       dispatch_suspend(queue);
    }
}

-(void) userResumes {
    if (queue) {
       dispatch_resume(queue);
    }
}

-(void) dealloc {
    if (queue) dispatch_release(queue);

    [super dealloc[;
}

March 27, 2013 Tutorialsios, objective-c, tutorial

Tutorial: Local Notifications

I know Push Notifications is all the rage lately, but let’s not forget about Local Notifications. They are much easier to implement and can sometimes be just as effective in getting Users to come back to your app. The short tutorial below will describe the steps needed to setup Local Notifications in your app.

Setup your Local Notification

The method below will set the notification to fire at a specific time. It doesn’t matter if the user has your app open or not. The notification will show up like most do on the device, usually a banner at the top of the screen that includes your app icon and a message. Users can change the alert style within “General Settings > Notifications > Your App Name”. Your notification will also appear in the device Notification Center.

-(void) setLocalNotification {
    
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    [comps setYear:2013];
    [comps setMonth:05];
    [comps setDay:01];
    [comps setHour:12];
    [comps setMinute:0];
    [comps setTimeZone:[NSTimeZone systemTimeZone]];
    NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate *setTime = [cal dateFromComponents:comps];
    
    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
    if (localNotif == nil)
        return;
    localNotif.fireDate = setTime;
    localNotif.timeZone = [NSTimeZone defaultTimeZone];
	
    // Notification details
    localNotif.alertBody = @"Don't forget to come back to the app name today for your bonus!";
    // Set the action button
    localNotif.alertAction = @"View";
	
    localNotif.soundName = UILocalNotificationDefaultSoundName;
    localNotif.applicationIconBadgeNumber = 1;
	
    // Schedule the notification
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}

To customize the code above change the NSDate entry to the date and time you would like your notification to fire. This method could easily be modified to take an NSDate parameter to allow you to call this method based on a dynamic date and time. Next you’ll want to change the alertBody to the message you want the user to see. It should contain a call to action so the user will be compelled to tap it to return to your app. SoundName can be changed to to accept an mp3 or wav if you wish. The example above uses the default sound setup on the users device. The application icon red badge bubble is then set to one to notify the user that their is a notification for you app that has not yet been tapped by them.

Cancelling All Notifications

You may want to include a toggle within your app to allow the user to turn off/on notifications. If the user turns notification off you should remove all notifications set so the user doesn’t receive them. Use the method below to remove all local notifications. If the user turns notifications back on then you’ll need to loop through your data recursively using the method above.

    // Cancel all Notifications
    UIApplication* app = [UIApplication sharedApplication];
    NSArray *notifications = [app scheduledLocalNotifications];
    if ([notifications count] > 0)
       [app presentLocalNotificationNow:notifications[0]];

Receiving the Notification

When a user taps on the notification they receive your app needs to handle it. irst the red bubble indicator on the app icon needs to be reset to zero. Then your app needs to handle the notification. This could be showing a specific view within your app (i.e. Give a user something free for coming back to your app if it’s a game). If you just want your app to open as normal, use the method below. This is handled in your app delegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    
    self.mainVC = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
    self.window.rootViewController = self.mainVC;
    [self.window makeKeyAndVisible];
    
    // Reset the Icon Alert Number back to Zero
    application.applicationIconBadgeNumber = 0;
    
    // Detect the Notification after a user taps it
    UILocalNotification *localNotif =
    [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    if (localNotif) 
    {
	NSLog(@"Recieved Notification %@",localNotif);
    }
    
    return YES;
}

- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
	// Handle the notification when the app is running
	NSLog(@"Recieved Notification %@",notif);
}
March 8, 2013 Tutorialsios, objective-c, tutorial

Tutorial: Setting up a Jenkins Automated Build Server for iOS

A Jenkins automated build server is one of the best ways to distribute a new build of your app to stakeholders and testers during the development, QA and UAT phases of the project. Jenkins is a highly customizable solution and best of all it’s FREE! The tutorial below will walk you through setting up and configuring the server plus adding a web server to help distribute the builds to the team. Note that the build will only work on devices that are included in your application provisioning profile (just like manually installing).

Installing Jenkins

The first time I tried installing Jenkins I downloaded the software from their website. Everything was going pretty well until I linked by GitHub account to the project. Jenkins wasn’t able to find the SSH key needed to automatically download the source code. The problem was that when the standard version of Jenkins is installed it creates it’s own user on the system and runs under the name “daemon”. Since it runs under another user, not your user it doesn’t have access to your GitHub SSH key. I searched all over for a solution to this and there are a ton of people who were having the same problem. I tried changing the user that Jenkins is running on, but in order to do that I needed to switch to the Jenkins user then give access to my user on the system, but I couldn’t find the Jenkins user password. Next I tried copying the SSH keys to the Jenkins user account, but that didn’t work either.

If you are like me and installed the standard Jenkins software and want to uninstall it from your system, use the commands below in Terminal to remove Jenkins from your system.

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
sudo rm -rf /Applications/Jenkins "/Library/Application Support/Jenkins" /Library/Documentation/Jenkins
sudo rm -rf /Users/Shared/Jenkins
sudo dscl . -delete /Users/jenkins
sudo dscl . -delete /Groups/jenkins

After a lot of searching, I found another solution. Sami Tikka created a new version of Jenkins that you can find on the jenkins-app Github that will install Jenkins under your current user account. This saved the day and made the rest of the setup for Jenkins so much easier. Once Jenkins is installed it will be hosted at http://localhost:8080, but also available publicly at http://<your IP address>:8080 so you can configure your server from anywhere you can access your IP from.

Configuring Jenkins

After Jenkins is installed we need to setup the plug-ins that we need for our server. Note that Jenkins can be used for many languages (including Java) and many source control systems (including CVS and Subversion). To access the plugins, click “Manage Jenkins” from the left side bar, then “Manage Plugins” from the list. Select the “Available” tab and check the following pluglins (Since we’re using GitHub and iOS):
1. GitHub API Plugin
2. GitHub Plugin
3. XCode integration

Let’s configure the system and enter in the details needed for the plugins to work. Select “Manage Jenkins” from the left side bar, then “Configure System” from the top of the list. You’ll notice the Home Directory at the top shows that Jenkins is installed under your user account, this means that the server can access all of your SSH keys and iOS Certificates from your user account. There isn’t much to change here, all of the defaults are good. Just enter your GitHub username and email address under the “Git plugin” section. Then scroll to the bottom and under “Git Web Hook” select “Let Jenkins auto-manage hook URLs” and enter your GitHub username and password. Click “Test Credential” to ensure that the server can verify you have the correct account information.
1359726962743

Setup your First Job

Now that the server is ready let’s setup our first project. Click “New Job” from the left side bar. Enter the name of your application and select “Build a free-style software project” and click “OK”. Under “Source Code Management” select “Git”, then enter your Git Repository URL. This URL must be the SSH URL found on GitHub, the HTTP URL will not work because the server cannot enter in the password needed. If you have not setup an SSH key for GitHub before, check out their tutorial on Generating SSH Keys.

To setup the Build Steps, click “Add Build Step” and select “XCode”. Check “Clean before build?”. Enter the “SYMROOT” to where the build will be stored (i.e. ${workspace}/build/<YourAppName>/Build/Products). Enter the “Configuration” to build the release from in your Xcode project (i.e. Debug or Release). Enter “${BUILD_NUMBER}” in the “Technical version” field. Check “Build IPA?” and “Unlock Keychain?”, then enter in your “Keychain path” as “${HOME}/Library/Keychains/login.keychain” and your password (which is your User password on your Mac). With this setup you will need to access the Jenkins server and select the “Build Now” option for the job. However if you would like to have an automated build you can setup those options under the “Build Triggers” section. It can “Build when a change has been pushed to GitHub” or “Build periodically” where it can be set to build at a specific time. An example for midnight is “0 0 * * *”. The first zero is the hour and the second is the minute to start the build.

We want to setup our server so the rest of the team can access the builds directly from their iPhone or iPad so we need to make a shell script that will copy the compiled IPA file to the web server so the team can access it. Click “Add Build Step” and select “Execute Shell”. Below is a shell script to get your started:

#!/bin/sh

export OTAURL="http://:8888/"
export OTASmallIcon=icon.png
export OTALargeIcon=icon.png
export OTADeployPath=~/Documents/JenkinsBuilds/
export OTATitle=

cp build//Build/Products/Release-iphoneos/*.ipa $OTADeployPath/.ipa
export info_plist=$(ls /-Info.plist | sed -e 's/\.plist//')
export bundle_version=$(defaults read $WORKSPACE/$info_plist CFBundleVersion)
cat << EOF > $OTADeployPath/.plist




items


assets


kind
software-package
url
$OTAURL/.ipa


kind
display-image
needs-shine

url
$OTAURL/icon.pn


kind
full-size-image
needs-shine

url
$OTAURL/icon.png


metadata

bundle-identifier
com..
bundle-version
$bundle_version
kind
software
title
$OTATitle





EOF

You’ll notice in the script above that you need to change the values of <YOUR PROJECT NAME> throughout. The OTADeployPath should be set to the path on your MAC that you set the web server root to (see more about that below). The “bundle-identifier” should be set to the Bundle Identifier set in your Xcode project.
mamp

Setting Up the Web Server

In order for the team to access the latest build they need to access it on their device. First, install MAMP on your MAC by selecting to download “MAMP: One-click-solution for setting up your personal webserver”. This is a FREE version for personal use. Once you have installed MAMP, change the Document Root to point to where you are copying the builds to in the OTADeployPath above. Once the Document Root is set you can “Start Servers” to begin. Next, create a simple index.html file to host in the Document Root.



Apps

Install App Name

To see your server enter http://<YOUR IP ADDRESS>:8888/ into your web browser. You should see the page above with a link to the IPA of your build.

Start Testing

The web server is setup, the automated build and shell script is set. Now let’s see if it works. Access your Jenkins server at http://<YOUR IP ADDRESS>:8080/, select your job and click the “Build Now” button from the left side bar. You’ll see the progress on the left side bar. Jenkins will attempt to access your Git repository to pull the latest code, then build it to create the IPA. Once it’s been compiled the shell script will copy the IPA to a project sub-directory under your web server document root directory. Then go to your web server URL http://<YOUR IP ADDRESS>:8888/ from your iPhone or iPad and click the link to install the app on your device. That should all work well but if you run into issues on the way be sure to check Jenkins for a reason why it failed. This information can be found under the “Build History” and clicking the “Console” icon on the right side of the table for the build that failed. Scroll down to the bottom of the output to see why it failed. Maybe it couldn’t copy the IPA correctly to your web server document root, ensure that they match.

Good luck with your automated builds. Once it’s setup and working it’ll be a valuable asset to your entire team to always have the latest version of your app without you having to manually install the app on their devices each time.

March 7, 2013 Tutorialstutorial

Tutorial: Designing and Exporting Your App Icon

After coding your app it’s time to make that killer icon that’s going to make your app stand out from the rest in the store. There are many things to consider to designing the best icon to fit your app.

Tips to Designing the Best App Icon

1. If your app is an already established brand, then it’s best to use that brand recognition in the icon by using the logo (i.e. Facebook, Twitter, Digg, etc..). If you don’t have a big brand then your icon should represent what the app does. Instagram is a good example since it shows that it’s a camera app.
2. Stay away from using text that’s longer than one word within the icon. It makes it very difficult to read when it’s sized down for the iPhone. It may read well in the 1024×1024 version of the icon, but test it on the phone to see if it’s still legible.
3. The design and colours of the icon should mimic the look of the app. It gives the experience that it’s truly a miniature representation of the app. When the user taps on the icon to open the app it should be a fluent transition of style.
4. Try to make your icon original. Since there are so many apps out there, yours may stand out if it looks different than the other ones in your category.
5. Emotion. You want your user to get an emotional connection to your app through the icon. You’ll notice that most of the top games all have a character or animal representing their game. That gives an emotional connection through the characters expression.

Icon Inspiration

Below are a couple links to collections of nice icons to give you an idea:
What Do the Top 100 Paid App Icons Have in Common?
iOS Icon Gallery
Icons Feed
iOS App Icon Designs (iOSpirations)
40 Brilliant iPhone & iPad Application Icons
45+ Fantastic iOS App Icon Designs for Inspiration

Exporting your Icon

Once you have designed your fabulous icon, you’ll need to export it to all the sizes required by Apple.

This is the best Photoshop template for creating iOS App Icons:
PixelReport’s App Icon Template
appicontemplatev2
With this template, you can see what your icon will look like in situation, within the app store and on the springboard. Then with a simple action all icons are saved out for you including in the proper naming conventions required.

March 6, 2013 Tutorialsdesign, ios, tutorial

Tutorial: Setting an Event in iCal

If you would need to programmatically set an event in the users Calendar you’ll need to leverage the EventKit framework API. The EventKit framework provides classes for accessing and manipulating calendar events and reminders.

First, access your target settings, click on “Summary”, scroll down to the “Linked Frameworks and Libraries” group and click the + button to add a new framework to your project. Search for ‘EventKit.Framework’.

Then you will be able to add a method like the one below to your class.

First add the EventKit framework to the top of your *.m file.

#import 

Next use the method below to set the iCal event.

-(void) setiCalEvent {

   // Set the Date and Time for the Event
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    [comps setYear:2013];
    [comps setMonth:3];
    [comps setDay:5];
    [comps setHour:9];
    [comps setMinute:0];
    [comps setTimeZone:[NSTimeZone systemTimeZone]];
    NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate *eventDateAndTime = [cal dateFromComponents:comps];

    // Set iCal Event
    EKEventStore *eventStore = [[EKEventStore alloc] init];

    EKEvent *event = [EKEvent eventWithEventStore:eventStore];
    event.title = @"EVENT TITLE";

    event.startDate = eventDateAndTime;
    event.endDate = [[NSDate alloc] initWithTimeInterval:600 sinceDate:event.startDate];

    // Check if App has Permission to Post to the Calendar
    [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (granted){
            //---- code here when user allows your app to access their calendar.
            [event setCalendar:[eventStore defaultCalendarForNewEvents]];
            NSError *err;
            [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
        }else
        {
            //----- code here when user does NOT allow your app to access their calendar.
            [event setCalendar:[eventStore defaultCalendarForNewEvents]];
            NSError *err;
            [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
        }
    }];
}

To customize it for your app, set the date and time of the iCal event, then change the event.title to what you want the user to see in their calendar, and finally the length of the event in seconds (i.e. 600 secs = 1 hour).

    [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (granted){
            //---- code here when user allows your app to access their calendar.

        }else
        {
            //----- code here when user does NOT allow your app to access their calendar.

        }
    }];

On iOS6, Apple introduced a new privacy control. The user can control permissions for the contact and calender by each app. So in the code side, you need to add some way to request the permission. In iOS5 or before, you can always call it without the user having to give permission.

March 5, 2013 Tutorialsios, objective-c, tutorial
Page 9 of 9« First«...56789
Recent Posts
  • Classix for iPhone, iPad & Apple TV
  • Tutorial: How to test your app for IPv6 compatibility
  • Tutorial: Testing SSL using Charles Proxy on an iOS Device
  • Tutorial: 3D Touch – Quick Actions in Swift
  • tvOS Tutorial: Top Shelf in Swift
Featured Apps
Classix
Sportsnet
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
Search
TAGS
tutorialswiftios8iosobjective-cvideogamesstrategynewsframeworkappsmonitizefacebookwatchappleios7toolstvosios9apiprovisionsocialtutorialsbooksdesignbookiapIPv6iTunes Connect
ABOUT
Brian is a Lead iOS/tvOS Developer from Toronto with over 18 years of multifaceted experience including development, design, business analysis and project management.

FOLLOW ME
    
Email Subscription
Sign up for my newsletter to receive the latest news and tutorials posted.

Enter your email address:

2023 © Brian Coleman