JSButton: A simple way to pass blocks to buttons and trigger them with a UIControlEvent

My friend Josh Sklar (a senior at Michigan, and soon to be full time iOS dev at Detroit Labs) wrote a very cool subclass of UIButton that allows you to pass a block to a button and have it executed with a given UIControlEvent.

For example, instead of creating a ton of selectors, you can now simply do:

JSButton *buttonOne = [[JSButton alloc]initWithFrame:CGRectMake((self.view.frame.size.width - kButtonWidth)/2, kLabelHeight, kButtonWidth, kButtonHeight)];
    [buttonOne setTitle:@"Buton One" forState:UIControlStateNormal];

    [buttonOne performBlock:^(id sender) {
        JSButton *btn = (JSButton*)sender;
        NSLog(@"Some trivial code for touching up inside on %@", btn.titleLabel.text);
    } forEvents:UIControlEventTouchUpInside];

    [self.view addSubview:buttonOne];

Here is a link to the repo: https://bitbucket.org/jrmsklar/jsbutton

Basic Model-View-Controller flow for iOS

So, one important thing to learn in iOS as well as in any language are some core concepts of software design. This would be the model view controller pattern.

In terms of an iOS project, a good way to think of how this could be implemented would be in a calculator application. The model of this project would store the methods that process the number, i.e. a method to add, a method to substract, a method that divides, and a method that multiples, etc.

For the sake of this application, lets assume each of the methods has an input of two doubles and returns a double as well. Essentially, our model will contain all the methods that do any action to the numbers in the calculator.

In our view controller, we will then make an instance of our model class. This will allow us to use all the instance methods we created in our model class in view controller class. Essentially, we want to pass the values from our view into the methods stored in our model.
Here is the header file:

 

//
//  CalculatorModel.h
//  ModelCalculator
//
//  Created by Andrew Rauh on 5/12/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface CalculatorModel : NSObject

- (double) addNumbers: (double) numberToAdd1 :(double) numberToAdd2;

- (double) subNumbers: (double) numberToSubtract1 :(double) numberToSubtract2;

@end

And here is the implementation file. (.m)


//
//  CalculatorModel.m
//  ModelCalculator
//
//  Created by Andrew Rauh on 5/12/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "CalculatorModel.h"

@implementation CalculatorModel

- (double) addNumbers: (double) numberToAdd1 :(double) numberToAdd2
{
    return (numberToAdd1+numberToAdd2);
}

- (double) subNumbers: (double) numberToSubtract1 :(double) numberToSubtract2
{
    return numberToSubtract1-numberToSubtract2;
}

@end

Now, we need to make an instance of this model class in our main view controller. So, do this:




//
//  ViewController.h
//  ModelCalculator
//
//  Created by Andrew Rauh on 5/12/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "CalculatorModel.h"

@interface ViewController : UIViewController {
    
    UIButton *button1;
    CalculatorModel *calculatorModel;
    
}


@property (nonatomic, strong) UIButton *button1;
@property (nonatomic, retain) CalculatorModel *calculatorModel;


@end


And finally, we will actually use and access these methods in our implementation file.

//
//  ViewController.m
//  ModelCalculator
//
//  Created by Andrew Rauh on 5/12/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize button1, calculatorModel;



- (void)viewDidLoad
{
    [super viewDidLoad];
    calculatorModel = [[CalculatorModel alloc] init];
    
    
    
    //Then you could pass in values from your view into the model methods. 
    //in this case I am just passing two arbitrary values into the method to test it. 
    [calculatorModel addNumbers:3.4455 :5.3];
    NSLog(@"%f",[calculatorModel addNumbers:3.4455 :5.3] );
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

@end

I realize this is exceptionally simple, but hopefully it showed the basics of this development pattern for iOS!