Brian Coleman

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

Ios 23

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

Tools: Optimizing your Images

You have finished all the code for your app, integrated the design, tagged everything for analytics, now you’re ready to release to the App Store right? Wrong. One of the last steps before finally releasing your new app is to optimize your images. This is important for two reasons. The first, it will slightly help the performance of your app. Since your views will be a little smaller they’ll load a little faster. You will especially notice this if you are supporting older devices (i.e. iPad 1st Gen and iPhone 4). Also if you have many assets on a view it should respond a little better. The second reason to optimize your images is the crucial 50 MB limit Apple sets for downloads over cellular networks. If your app is over 50 MB users will not be able to download your app unless they are on a Wi-Fi network. This is a barrier that you can’t afford, anything stopping a user from downloading your app may cost you that download if they forget about your app or move onto the one next to it that’s similar in the store.

ImageOptim

The tool that I use is ImageOptim, it’s a really easy tool to use and it’s FREE! ImageOptim optimizes images — so they take up less disk space and load faster — by finding best compression parameters and by removing unnecessary comments and color profiles. It handles PNG, JPEG and GIF animations. Most importantly it does so without affecting the image quality.

The interface to ImageOptium is very minimal and simple. Drag images onto its window or dock icon, or click on the plus (+) button to select images from a standard open dialog box. The app immediately starts optimizing the images, using one or more of a slew of command-line image optimization tools: PNGOUT, AdvPNG, Pngcrush, extended OptiPNG, JpegOptim, jpegrescan, jpegtran, and Gifsicle. Beside each file name you’ll see the file size (in bytes), and the percentage by which the file size was shrunk from the original and at the bottom it will tell you the total amount of savings for all the images you optimize at once.

ShrinkIt

Another great tool for optimizing images is ShrinkIt. The difference between ImageOptim and ShrinkIt is ShrinkIt allows you to optimize PDFs. If you have a magazine app or a PDF reader it will be quicker for users to download your PDFs if they are smaller.

shrinkit

ShrinkIt is a simple, small tool (for Mac OS X Snow Leopard) that will automate the process of stripping needless metadata from PDFs by re-saving them using Apple’s PDF processor. This is 100% lossless – it’s not compressing anything, just removing unneeded data. Simply drop a bunch of files onto it to have it do its magic. The original files will be renamed with the prefix “_org_” for safety, but you’ll probably just want to delete them.

Both of the apps above are great for reducing the size of your images and PDFs without losing any quality, so why wouldn’t you optimize?

March 14, 2013 Toolsdesign, ios, tools

Framework: Flurry Analytics

With every app that you release you should include an analytics framework. It’s important for you to know how many people downloaded your app, how many are actually using it, how often they are using it and what they are using in it. You spend all this time developing killer features but do your users care? One of the most important strategies around apps is to constantly improve your product. Your app may not be a #1 app the first time you release it, but if you constantly improve the usability based on what users are doing in your app then it’ll start climb the charts and get better word of mouth. Focus on enhancements to the areas of your app that users like the most.
omniture_550b
When you’re testing your app yourself and with your family and friends you get a little feedback, but until you have a user base of at least a thousand users it’s tough to know for sure, you don’t have enough data to conclude how most people will use your app. By tagging the right events in your app you can get a good sense of the funnel users are taking and optimize the users experience based on that data.

Analytics Tools

There are three major companies for App Analytics. The first is Omniture. It’s been around for a very long time and has been a best in class suite for the biggest websites. If you are working on an app for a top brand and their website is currently being tracked using Omniture, this is probably the best way to go since the investment has already been made. Omniture is a very expensive suite and typically only used by big business.

Another popular way to track analytics in apps is using Google Mobile App Analytics. For many users they already have for web and mobile web analytics, it makes total sense to keep using the same tool they’re used to for in-app usage analytics. The best thing about it is it’s FREE!

The tool that I use in all of my personal apps and the one we’re going to focus on is Flurry Analytics. Flurry is a complete tool for your mobile app analytics. With Flurry, you can filter via segments (age, first session, usage, country, etc), app versions and dates. Because Flurry offers lots of other services (like ads), this tool is free yet provides a lot of analytics.

Here’s the kind of info you can find or use in the dashboards:
– Usage: active users, sessions, session lengths, frequency, retention, etc.
– Audience: interest of users(your other apps + category), personas (type of your users – defined by Flurry), demographic
– Events: define events, see user paths, create funnels
– Technical: devices, carriers, firmware versions, errors

Setting up Flurry Analytics

Follow the steps below to get started with Flurry:
1. Visit www.flurry.com and sign up, don’t worry it’s FREE!
2. Click the “Applications Tab” then “Create a New Application” and Select the Platform your app is on (iPhone or iPad).
3. Enter the Name and Category your application will be submitted to within the App Store.
4. Make sure you copy the unique application key (API KEY), you’re going to need it soon.
5. Download the Flurry SDK.
6. Copy the Flurry Library (Flurry.h and libFlurry.a) files into your project.
7. Add the following code into your App Delegate.

#import "Flurry.h"
- (void)applicationDidFinishLaunching:(UIApplication *)application 
{
     [Flurry startSession:@"YOUR_API_KEY"];
     //your code
}

8. Start tagging the events within your application

[FlurryAnalytics logEvent:@"Start_Button_Pressed"];

You can track up to 300 Events for each application so track everything you can. Add the event tag above to every method you have in your project. You should be tracking every button pressed by the user, every page view, every completed stage, every ad clicked and every step to in-app purchases. Once you have that done, run your app a couple times and look within Flurry Reports in an hour or so to see if you’re capturing data. Once you launch your next app check back with Flurry to see how many active users are using your app, what kind of device they have, what iOS version and what country they are from. With all of this data plus all of the events you’ve tagged you will get a holistic view into how users are using your app, then you can optimize and continue to improve in your next update.

March 13, 2013 Frameworksframework, ios, objective-c

Framework: MTLabel

Not too long ago I needed to build a table of contents using a table view controller. It displayed a page title and a description. Our designer asked if I could change the leading in the line spacing for each. My initial response was no that can’t be done using a UILabel because the leading is automatic based on the size and font. I started to look for solutions and the only one I could come up with was to calculate the number of characters then break the title out into multiple UILabels. After more thought it would be more difficult to detect where to break it since it would have to break after a word, not just in the middle of a word, so I continued to search for a solution. Then I found MTLabel.

Change the Leading of your Label

MTLabel is a great framework built by Michal Tuszynski. It allows you to customize line spacing, specify if you want the label to resize itself based on text height and supports almost all features of UILabel. It actually is a UIView that you sub-class with type MTLabel. This was very useful and now I’m using it all the time when I need to make wrapping text look good with the right amount of line spacing.

First, you’ll need to integrate the framework into your project.
1. Download the source code from the MTLabel GitHub.
2. Add the following files into your project:
– MTLabel.h
– MTLabel.m
3. Add the “CoreText.framework” framework to your project. To do this, 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 “CoreText.framework”.
4. Include the following header at the top of your class:

#import "MTLabel.h"

4. Start coding!

MTLabel *titleLabelView = [MTLabel labelWithFrame:CGRectMake(15, 4, 252, 100) andText:@"This is where you place the text you need to wrap"];
[titleLabelView setFontColor:[UIColor blackColor]];
[titleLabelView setFont:[UIFont fontWithName:@"Helvetica-Bold" size:19.0]];
[titleLabelView setLineHeight:18];
[self.view addSubview:titleLabelView];

The code above shows a basic implementation of MTLabel. Define the frame of your label and the text, then style the font color and finally set the line height to the space you would like between the lines. Look at that, a lot nicer than UILabel.

Resizing MTLabels and Table View Cells

The example above works well if you know how much text you have and the exact space you have to place the label, but what if you need dynamic text like my table of contents example. Implementing this in a table view controller is a little tougher because each title and description can be different. The method below will calculate the height of the text view needed based on the font and width provided.

-(CGSize) calcLabelSize:(NSString *)string withFont:(UIFont *)font  maxSize:(CGSize)maxSize{
    return [string sizeWithFont:font constrainedToSize:maxSize];
}

Let’s see this method in action below. We’ll calculate the expected height that we need the MTLabel to be based on what is returned from the method above.

CGSize titlemax = CGSizeMake(250, 100);
CGSize titleexpected = [self calcLabelSize:[toc name] withFont:[UIFont fontWithName:@"Helvetica-Bold" size:19.0] maxSize:titlemax];

MTLabel *titleLabelView = [MTLabel labelWithFrame:CGRectMake(15, 4, 252, titleexpected.height) andText:[toc name]];
[titleLabelView setFontColor:[UIColor blackColor]];
[titleLabelView setFont:[UIFont fontWithName:@"Helvetica-Bold" size:19.0]];
[titleLabelView setLineHeight:18];
[cell addSubview:titleLabelView];

Notice that the height of the MTLabel is being set by “titleexpected.height” which was calculated using the “calcLabelSize” method. If you are using a table view controller you’ll also need to calculate and resize the cell height based on the font as well.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  NSString *key = [[_sections objectAtIndex:[indexPath section]] sectionName];
  NSArray *items = [_titles objectForKey:key];
  ClassName *toc = [items objectAtIndex:[indexPath row]];
  CGSize max = CGSizeMake(250, 100);
  CGSize expected = [self calcLabelSize:[toc name] withFont:[UIFont fontWithName:@"Helvetica-Bold" size:19.0] maxSize:max];
  return expected.height;
}

I hope this short tutorial helped you dynamically set the height of a text label and make it look nice with the proper line spacing.

March 12, 2013 Frameworksframework, ios, objective-c

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
Page 4 of 5«12345»
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