D3 / JavaScript Swift & iOS | JavaScriptCore Framework

Why would you ever want to use JavaScript in your Swift Project?

javascript-sucks I am working on a project that started off as a web application first. It has a lot of cool features and some pretty advanced graphs. Their front end developer is using d3.js. D3.js is a JavaScript library for manipulating documents based on data. D3 is an amazing library that can do just about any kind of graph imaginable from circle packing to basic line graphs, and what is even more impressive is it was written by one guy Mike Bostock. Anyway in addition to awesome graphs there are a lot of helpful functions for calculating all kinds of data, and the front end developer on my project was using these. I thought no problem I can just translate these methods into swift and be able to reproduce the same data! Easy peasy lemon cheesy right. Wrong… Mike Bostock is a genius and I found out how incompetent I am at math!

A real world application

So in this application there is a graph that displays your co workers based on how much you interact with them based on email and slack conversations. The data base returns a score with each contact from 1 to 10 and according to that score the user is place in one of three rings the circle closet to you being those that you work with the most and the outer circle being the one that you work with the least. D3 has some really handy Quantitative Scales that the front end developer used to get which circle the co worker should be placed in. So after hours of trying to figure out how the hell Mike wrote these awesome scales I decided to embrace my hate, turn to the dark side and just use javascript in my project.
ain't nobody

JavaScriptCore Framework

Available since iOS 7 JavaScriptCore is the built-in JavaScript engine for WebKit. It currently implements ECMAScript as in ECMA-262 specification. It allows for an easy and fast way to interact with JavaScript.
To get started you first need to load in the d3 library. Also in this first step we are going to add error handling so we are able to see what we are doing wrong with our javascript which can be very handy!

// get a reference to the d3 library in our project
let fileLocation = NSBundle.mainBundle().pathForResource("d3.min", ofType: "js")!
// convert it to a string
let jsSource: String = try! String(contentsOfFile: fileLocation)
// create a javascript context environment
let context = JSContext()
// add exception handler so we can see any error that occur in our javascript
context.exceptionHandler = { context, exception in
    print("JS Error: \(exception)")
}
// load in the javascript into our context
context.evaluateScript(jsSource)

Once d3 is loaded we can access it exactly like you would in a HTML file

// create our javascript function for the linear scale we also mix in swift with the maxAmount variale
context.evaluateScript("circles = d3.scale.quantize().domain([0,\(maxAmount)]).range([3, 2, 1])")

// loop through all the contacts to determine which circle they should be placed in
for contact in contacts {
    // get the circle number based on score it will return 1, 2 or 3
    let circle: JSValue = context.evaluateScript("radius_circles(\(contact.score))");
    //  cast the JSValue to Int
    contact.circle = Int(circle.toInt32())
}
// sort the contacts array based on the new circle value
self.contacts.sortInPlace({ $0.circle < $1.circle })

Success

Thats all there is to it! Now we have data that matches the web app so we can successful show the same rankings and data in the iOS app! I don't think I would use this very often but I think it is very handy to have as an extra tool in your tool box. Let me know in the comments below what you guys think to this approach and if you would ever use javascript in your project

Lets be friends

I love meeting new iOS friends online so follow me on twitter
. Please stop by and say hello!

Dynamic UITableViewCell Height | Swift

Working as an iOS developer since iOS 4 I have been able to see lots of changes like the introduction of ARC, auto layout, storyboards, size classes and swift. Working for agencies I am always amazed at how long it takes some companies to adopt these new tools, a lot of which make your life easier and reduce the amount of code you have to write. Today I’m going to be talking about how easy it is to create a UITableViewCell that has a dynamic height based on the content in the cell using Auto Layout. If you want to follow along with project you can download the it from github. Also if you have any questions send me a tweet over at
or leave a comment below.

Setting up the UITableViewCell

First thing we do is set up the view. I have a UITableView in my view and since I’m using a storyboard I can prototype the cell right in the table view. I add two UILabels that will hold the cell’s content. Here is what we have so far:
Storyboard with UITableView and prototype cell
Next we need to add the constraints to the labels. Since we want them to resize depending on how much text is in them we are going to set leading, trailing, top, and bottom spacing constraints. The First Label will look like this:
Screen Shot 2015-04-05 at 2.19.36 PM
And the second label’s constraints will look like this:
Screen Shot 2015-04-05 at 2.22.13 PM
The constraints in Label 1 are letting the view know each label has a margin of about 8 points to the top, leading and trailing spacing and another 8 points to the label below it. So now matter how the height of the label to keep it spacing. The constraints in Label 2 are doing pretty much the same thing except the top spacing is referring to the label above it and the bottom spacing is referring to the parent view.

Don’t forget to set the number of lines in the label to 0 and line breaks to word wrap so the label can have multiple lines of text

Setting up the UITableView

In the view controller we created an IBOutlet for the table view and there is only one thing we have to do differently and it’s letting the talbe view know it will be using dynamic heights for each cell.

self.tableview.rowHeight = UITableViewAutomaticDimension 

Once that is done we just handle it like a normal UITableView and UITableViewCelll no need to sizeToFit or calculate height for heightForRowAtIndexPath! Here is what the completed ViewController looks like:

//
//  ViewController.swift
//  Dynamic-Cell-Height
//
//  Created by Barrett Breshears on 4/5/15.
//  Copyright (c) 2015 Barrett Breshears. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet var tableview:UITableView!
    var tableViewData:[String] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.tableview.rowHeight = UITableViewAutomaticDimension 
        
        self.tableViewData.append("Bacon ipsum dolor amet venison pork chop beef tri-tip meatball andouille. Biltong cupim turducken turkey pig, picanha shankle porchetta salami ham hock venison. Bresaola salami sausage corned beef jowl meatball spare ribs chuck short loin chicken. Bacon ham hock swine leberkas salami porchetta kielbasa shankle.")
        self.tableViewData.append("Landjaeger ham hock kevin shankle, sirloin bacon jowl meatball tail. Frankfurter ham chicken corned beef meatloaf ground round pork loin turkey tenderloin cow pork filet mignon bacon short ribs jerky. Drumstick bresaola picanha tail. Ribeye tail landjaeger, sausage pork belly biltong flank shank fatback cow meatloaf. Frankfurter short loin pancetta turkey t-bone, pork chop sirloin. Sirloin pork loin boudin spare ribs pastrami. Pig brisket sirloin chuck turkey.")
        self.tableViewData.append("Spare ribs cupim prosciutto hamburger kevin strip steak pastrami bresaola ham turducken pork kielbasa picanha. Cupim strip steak chicken pork belly beef ribs. Pork chop strip steak flank tenderloin short loin bacon corned beef cupim ground round venison doner ham chicken tail beef. Corned beef cupim tenderloin doner prosciutto filet mignon. Tail ham hock ham hamburger shankle landjaeger sirloin, brisket tongue t-bone pork. Beef ribs porchetta alcatra hamburger, chicken filet mignon ground round ham ball tip shank turducken pork chop. Ham hock venison t-bone frankfurter prosciutto, doner drumstick shankle ball tip tenderloin ribeye.")
        self.tableViewData.append("Frankfurter ham spare ribs turducken venison biltong. Tenderloin kevin flank pork loin capicola. Pastrami tenderloin kevin, turducken beef ribs salami cupim short ribs. Pork flank cupim, meatloaf tail leberkas tri-tip filet mignon tenderloin turducken beef salami.")
        self.tableViewData.append("Doner ball tip meatball shoulder tongue shankle chicken. Ground round turducken kielbasa, chicken meatloaf flank corned beef chuck rump hamburger spare ribs. Beef ribs pork belly filet mignon meatloaf, corned beef andouille tri-tip jerky turkey biltong alcatra ham hock. Alcatra meatloaf capicola, drumstick cupim spare ribs boudin meatball kevin cow ribeye porchetta beef ribs. Cupim alcatra beef pork chop pork belly ground round capicola salami turkey shankle tenderloin chicken frankfurter landjaeger. Cow hamburger meatloaf pancetta bacon rump, venison pork belly kielbasa kevin.")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as? CustomTableViewCell;
        
        var data:String = self.tableViewData[indexPath.row] as String!
        cell?.label1.text = data
        cell?.label2.text = data
        
        return cell!;
        
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableViewData.count
    }
    

}

Thats it! I think this simple example really shows how much you can do with Auto Layout, and if you have been to busy or just more comfortable using springs and struts you consider learning Auto Layout and constraints. If you enjoyed this post I would really appreciate it if you share it with your friends. Also I am always looking for iOS developer friends follow me on twitter and send me a tweet if you ever want to talk about anything, please no android developers (just kidding).

AWS S3 Image upload using AWS SDK for iOS v2

Hi there and welcome. Today we will be talking about AWS S3 Image upload using AWS SDK for iOS v2 (WOW thats a lot of acronyms!). Last week I had to do this in a project and it took me and I was disappointed with the documentation, and sample project they had available. So in this tutorial I’m going to be showing a real world example where you would select an image from the gallery or take a photo on a device and upload that image to your bucket. If you want to follow along I have the projects available on github for both objective-c and swift! I also have a video of setting up S3 and Amazon Cognito at the end of the tutorial, but I have to apologize for the quality. I am terrible at making videos, and I was very tired when I made it (also my voice is very annoying).

Github Links

Also don’t forget to follow me on twitter if you ever want to chat about iOS or mobile development! .

Set up credentials

First thing we need to do is set up amazons credentials your app delegate’s didFinishLaunchingWithOptions method. In this demo we are going to use Cognito to manage access to our S3 bucket. If you want a full in depth look at how to do this watch the video at the end of the tutorial.

Objective-C

AppDelegate.m

//
//  AppDelegate.m
//  s3-objectiveC
//
//  Created by Barrett Breshears on 12/5/14.
//  Copyright (c) 2014 Barrett Breshears. All rights reserved.
//

#import "AppDelegate.h"
#import "AWSCore.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider
                                                          credentialsWithRegionType:AWSRegionUSEast1
                                                          accountId:@"#######"
                                                          identityPoolId:@"######"
                                                          unauthRoleArn:@"#####"
                                                          authRoleArn:@"######"];
    
    AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1
                                                                          credentialsProvider:credentialsProvider];
    
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

@end

Swift

AppDelegate.swift

//
//  AppDelegate.swift
//  s3-swift
//
//  Created by Barrett Breshears on 12/6/14.
//  Copyright (c) 2014 Barrett Breshears. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        var credentialsProvider:AWSCognitoCredentialsProvider = AWSCognitoCredentialsProvider.credentialsWithRegionType(AWSRegionType.USEast1, accountId:"##########", identityPoolId:"#######", unauthRoleArn:"#######", authRoleArn:"########")
        
        var configuration:AWSServiceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
        
        AWSServiceManager.defaultServiceManager().setDefaultServiceConfiguration(configuration)
        
        
        
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
    }

    func applicationDidEnterBackground(application: UIApplication) {
    }

    func applicationWillEnterForeground(application: UIApplication) {
    }

    func applicationDidBecomeActive(application: UIApplication) {
    }

    func applicationWillTerminate(application: UIApplication) {
    }


}

This is a pretty simple set up here, and if you configure your credentials in the Cognito console it will actually give you the code to set up your configuration.

Upload an image to S3

So the main difference between v1 and v2 is that you used to be able to set the upload body request to NSData or a NSURL. In v2 you can only set the upload request to a NSURL. So what we have to do is save the image to the app’s local directory and then we can create a local file url to send to amazon.

Objective-C
- (void)uploadToS3{
    // get the image from a UIImageView that is displaying the selected Image
    UIImage *img = _selectedImage.image;
    
    // create a local image that we can use to upload to s3
    NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"image.png"];
    NSData *imageData = UIImagePNGRepresentation(img);
    [imageData writeToFile:path atomically:YES];
    
    // once the image is saved we can use the path to create a local fileurl
    NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
    
    // next we set up the S3 upload request manager
    _uploadRequest = [AWSS3TransferManagerUploadRequest new];
    // set the bucket
    _uploadRequest.bucket = @"s3-demo-objectivec";
    // I want this image to be public to anyone to view it so I'm setting it to Public Read
    _uploadRequest.ACL = AWSS3ObjectCannedACLPublicRead;
    // set the image's name that will be used on the s3 server. I am also creating a folder to place the image in
    _uploadRequest.key = @"foldername/image.png";
    // set the content type
    _uploadRequest.contentType = @"image/png";
    // we will track progress through an AWSNetworkingUploadProgressBlock
    _uploadRequest.body = url;
    
    __weak ViewController *weakSelf = self;
    
    _uploadRequest.uploadProgress =^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend){
        dispatch_sync(dispatch_get_main_queue(), ^{
            weakSelf.amountUploaded = totalBytesSent;
            weakSelf.filesize = totalBytesExpectedToSend;
            [weakSelf update];
            
        });
    };
    
    // now the upload request is set up we can creat the transfermanger, the credentials are already set up in the app delegate
    AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
    // start the upload
    [[transferManager upload:_uploadRequest] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
        
        // once the uploadmanager finishes check if there were any errors
        if (task.error) {
            NSLog(@"%@", task.error);
        }else{// if there aren't any then the image is uploaded!
            // this is the url of the image we just uploaded
            NSLog(@"https://s3.amazonaws.com/s3-demo-objectivec/foldername/image.png");
        }
        
        return nil;
    }];
    
}
Swift
 func uploadToS3(){
        
        // get the image from a UIImageView that is displaying the selected Image
        var img:UIImage = selectedImage!.image!
        
        // create a local image that we can use to upload to s3
        var path:NSString = NSTemporaryDirectory().stringByAppendingPathComponent("image.png")
        var imageData:NSData = UIImagePNGRepresentation(img)
        imageData.writeToFile(path, atomically: true)
        
        // once the image is saved we can use the path to create a local fileurl
        var url:NSURL = NSURL(fileURLWithPath: path)!
        
        // next we set up the S3 upload request manager
        uploadRequest = AWSS3TransferManagerUploadRequest()
        // set the bucket
        uploadRequest?.bucket = "s3-demo-swift"
        // I want this image to be public to anyone to view it so I'm setting it to Public Read
        uploadRequest?.ACL = AWSS3ObjectCannedACL.PublicRead
        // set the image's name that will be used on the s3 server. I am also creating a folder to place the image in
        uploadRequest?.key = "foldername/image.png"
        // set the content type
        uploadRequest?.contentType = "image/png"
        // and finally set the body to the local file path
        uploadRequest?.body = url;
        
        // we will track progress through an AWSNetworkingUploadProgressBlock
        uploadRequest?.uploadProgress = {[unowned self](bytesSent:Int64, totalBytesSent:Int64, totalBytesExpectedToSend:Int64) in
            
            dispatch_sync(dispatch_get_main_queue(), { () -> Void in
                self.amountUploaded = totalBytesSent
                self.filesize = totalBytesExpectedToSend;
                self.update()

            })
        }
        
        // now the upload request is set up we can creat the transfermanger, the credentials are already set up in the app delegate
        var transferManager:AWSS3TransferManager = AWSS3TransferManager.defaultS3TransferManager()
        // start the upload
        transferManager.upload(uploadRequest).continueWithExecutor(BFExecutor.mainThreadExecutor(), withBlock:{ [unowned self]
            task -> AnyObject in
            
            // once the uploadmanager finishes check if there were any errors
            if(task.error != nil){
                NSLog("%@", task.error);
            }else{ // if there aren't any then the image is uploaded!
                // this is the url of the image we just uploaded
                NSLog("https://s3.amazonaws.com/s3-demo-swift/foldername/image.png");
            }
            
            self.removeLoadingView()
            return "all done";
        })
        
    }

Once you understand how to configure your credentials and how to get the image from an image view to local file to url to amazon the process is pretty simple. Please let me know if you have any questions in the comments below or on send me a tweet
.

Setting up credentials and project walk through video

Create Custom Delegate and Protocol iOS | Swift & Objective-C

One of the most powerful tools an iOS developer has is the ability to create protocols and implement delegates that let your classes notify when an event occurs. I use them all the time in my projects and wanted to show how easy it is to implement your iOS Project. I will demonstrate them in both Objective-C and Swift so you can see a side by side comparison. In this example we will be implementing timer that fires a timerFinished method to let the UIViewController know the timer finished and start the timer over.

If you want to follow allow you can download the projects from GitHub here:

Objective-C  Project
Swift Project

Protocols

A protocol is a list of methods that specify an interface that your delegate will implement. There are two kinds of delegates we can use: Option and Required. They are pretty self explanatory but the difference is Required will throw an error letting you know your class is not conforming to the protocol. Also protocol methods are required by default so if you want it optional don’t forget that optional keyword. If you are using swift you will also need to add the @objc prefix if you want an optional method.

Swift
//
//  MyTimer.swift
//  SwiftProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

import UIKit

// set up the MyTimerDelegate protocol with a single option timer finished function
@objc protocol MyTimerDelegate{
    optional func timerFinished()
}


class MyTimer: UIViewController {
    
    // this is where we declare our protocol
    var delegate:MyTimerDelegate?
    
    // set up timer variables and labels
    var timer:NSTimer! = NSTimer()
    var labelTimer:NSTimer! = NSTimer()
    var timerLabel:UILabel! = UILabel()
    var timerCount = 0
    var duration = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        timerLabel = UILabel(frame: self.view.frame)
        timerLabel.textAlignment = NSTextAlignment.Center
        self.view.addSubview(timerLabel)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func startTimer(timerDuration:Double){
        self.duration = Int(timerDuration)
        timerLabel.text = String(format: "%d", duration)
        
        timer = NSTimer.scheduledTimerWithTimeInterval(timerDuration, target: self, selector: Selector("timerFired:"), userInfo: nil, repeats: false)
        
        labelTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateLabel:"), userInfo: nil, repeats: true)
        
        
    }
    
    func timerFired(timer:NSTimer){
        if(timer.valid){
            timer.invalidate()
        }
        if(labelTimer.valid){
            labelTimer.invalidate()
        }
        // ************************************** \\
        // ************************************** \\
        // This is the important part right here
        // we want to call our protocol method
        // so the class implementing this delegate will know
        // when the timer has finished
        // ************************************** \\
        // ************************************** \\
        delegate?.timerFinished!()
        
    }
    
    func updateLabel(timer:NSTimer){
        duration = duration - 1
        timerLabel.text = String(format: "%d", duration)
    }
    
    
    /*
    // MARK: - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    }
    */
    
}

This is a pretty simple example but here is what is going on. The UIViewController has a start timer method that sets up the two timers: one that will fire when the overall time is complete and one that fires every second to update the timer label. When the total duration timer is finished the timerFired method is called, and thats where we run the delegate’s timerFinished method. Now lets do the same thing but with Objective-C.

Objective-C
//
//  MyTimer.h
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import 

// set up the MyTimerDelegate protocol with a single option timer finished function
@protocol MyTimerDelegate 

@optional
-(void)timerFinished;

@end

@interface MyTimer : UIViewController
// this is where we declare our protocol
@property (nonatomic, strong) id delegate;
// set up timer variables and labels
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) NSTimer *labelTimer;
@property (nonatomic, strong) UILabel *timerLabel;
@property (nonatomic, assign) int timerCount;
@property (nonatomic, assign) int duration;

- (void)startTimer:(float)duration;

@end

//
//  MyTimer.m
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import "MyTimer.h"



@interface MyTimer ()

@end

@implementation MyTimer

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _timer = [[NSTimer alloc] init];
    _labelTimer = [[NSTimer alloc] init];
    _timerCount = 0;
    _duration = 0;
    
    
     _timerLabel = [[UILabel alloc] initWithFrame:self.view.frame];
    [self.view addSubview:_timerLabel];
    [_timerLabel setTextAlignment:NSTextAlignmentCenter];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)startTimer:(float)duration{
    _duration = (int)duration;
    _timerLabel.text = [NSString stringWithFormat:@"%d", _duration];
    
    _timer = [NSTimer scheduledTimerWithTimeInterval:duration
                                              target:self
                                            selector:@selector(timerFired:)
                                            userInfo:nil
                                             repeats:NO];
    
    _labelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                   target:self
                                                 selector:@selector(updateLabel:)
                                                 userInfo:nil
                                                  repeats:YES];
    
    
}

- (void)timerFired:(NSTimer *)timer {
    if ([_timer isValid]) {
        [_timer invalidate];
    }
    _timer = nil;
    if ([_labelTimer isValid]) {
        [_labelTimer invalidate];
    }
    _labelTimer = nil;
    // ************************************** \\
    // ************************************** \\
    // This is the important part right here
    // we want to call our protocol method here
    // so the class implementing this delegate will know
    // when the timer has finished
    // ************************************** \\
    // ************************************** \\
    [_delegate timerFinished];
}

- (void)updateLabel:(NSTimer *)timer{
    _duration = _duration - 1;
    _timerLabel.text = [NSString stringWithFormat:@"%d", _duration];
}

@end

So same thing just different syntax. The UIViewController has a start timer method that sets up the two timers: one that will fire when the overall time is complete and one that fires every second to update the timer label. When the total duration timer is finished the timerFired method is called, and thats where we run the delegate’s timerFinished method.

Delegates

Now that we have our protocols all set up all we have to do is implement them. We are going to do this by creating a delegate. A delegate is a variable that complies to a protocol, which a class typically uses to notify of events, in this case the timer finishing. To do this we add our protocol to our class declaration, to let our class know it must comply with the delegate. Then we add our delegate method to our class.

Swift
//
//  ViewController.swift
//  Swift-Protocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

import UIKit

// add our MyTimerDelegate to our class
class ViewController: UIViewController, MyTimerDelegate {
    
    var timer:MyTimer = MyTimer()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        timer.view.frame = self.view.frame
        // ************************ \\
        // This is where we let the delegate know 
        // we are listening for the timerFinished method
        // ************************ \\
        timer.delegate = self
        self.view.addSubview(timer.view)
        timer.startTimer(10.0)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // ************************ \\
    // This is where our delegate method is fired
    // ************************ \\
    func timerFinished(){
        timer.startTimer(10.0)
        println("Hey my delegate is working")
    }

}

So the important thing here is we set the timer.delegate to self so the ViewController’s method timerFinished() class is called.

Objective-C
//
//  ViewController.h
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/10/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import 
#import "MyTimer.h"

// add our MyTimerDelegate to our class
@interface ViewController : UIViewController 

@property (nonatomic, strong) MyTimer *timer;

@end
//
//  ViewController.m
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/10/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _timer = [[MyTimer alloc] init];
    _timer.view.frame = self.view.frame;
    _timer.delegate = self;
    [self.view addSubview:_timer.view];
    [_timer startTimer:10.0];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)timerFinished{
    [_timer startTimer:10.0];
    NSLog(@"Hey my delegate is working!");
}

@end

When we run the code we see the timer label is added and set to a 10 second timer. It counts down, and when it reaches 0 it notifies the viewcontroller, restarts the timer and prints the “Hey my delegate is working in the console”.

If you have any questions about the code or found this tutorial helpful let me know in the comments below! I appreciate feedback. Also don’t forget to follow me on twitter. I am always looking for iOS developers to tweet with.

CoreLocation iOS 8 and Swift

I started my first swift app with iOS 8 and needed to use core location, something that I haven’t used in a really long time. After writing all the code and testing out the app I couldn’t get the dang thing to use my location! After a frustrating 30 min of debugging I figured out what the issue is and decided to write this post to hopefully help you avoid that frustration. So here is what you need to do to get core location working with iOS 8 and swift.

CoreLocation Project setup

Add the CoreLocation.framework to your project

First step is to select your project in the project navigator, and select your project target. Once selected expand the link binary and click the add items button. Choose the CoreLocation.framework from the pop up window.
Screen Shot 2014-10-09 at 7.14.55 AM

Editing Info.plist

This is where I screwed up in my attempt, I forgot to add the property key in my plist. This caused the app not to get my location, and it didn’t give any warning or error to let me know there was even a problem. So add NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription key in your Info.plist file to indicate the level of authorization you require. NSLocationWhenInUseUsageDescription will allow you to get the device location when you are using the app and NSLocationAlwaysUsageDescription will allow you to get the device location when you are using the app as well as in the background when the app isn’t running. The key you set is what will be displayed in the pop up asking for permission. Also as a side note if you need to localize your plist here is apple’s docs on how to do that Localizing Property List Values. I only need to use location while the app is in use so I used NSLocationWhenInUseUsageDescription and only wanted apple’s default message so I left the value blank.
Screen Shot 2014-10-09 at 7.37.09 AM

Create your view controller and add the CLLocationManagerDelegate

Now that we have all that project setup done we can get on to the code. So first step is to add the CLLocationManagerDelegate to your view controller, implement these delegate methods. Then init your CLLocationManager and start receiving your location data.

//
//  MapViewController.swift
//
//  Created by Barrett Breshears on 10/6/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

import UIKit
import CoreLocation

class MapViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        if (CLLocationManager.locationServicesEnabled()) {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestWhenInUseAuthorization()
            locationManager.startUpdatingLocation()
        } else {
            println("Location services are not enabled");
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    // MARK: - CoreLocation Delegate Methods
    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        locationManager.stopUpdatingLocation()
        removeLoadingView()
        if ((error) != nil) {
            print(error)
        }
    }
    
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locationArray = locations as NSArray
        var locationObj = locationArray.lastObject as CLLocation
        var coord = locationObj.coordinate
        println(coord.latitude)
        println(coord.longitude)
    }
}

Let me know if there are any questions or comments about the code or the project setup. Also don’t forget to follow me on twitter! I’m always looking for new internet friends.