Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Adam Milligan

iPhone on blocks: UITextFields

Adam Milligan
Saturday, August 7, 2010

If you’ve ever used a UITextField in an iPhone project (or, I suppose, an NSTextField in a Cocoa project) you know that you pass it a delegate object in order to respond to events. Handling the “Return” key press from the on-screen keyboard may look something like this (probably implemented in your view controller):

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (0 == [textField.text length]) {
        return NO;
    }
    [self doSomethingWithText:textField.text];
    [textField resignFirstResponder];
    return YES;
}

The delegate pattern is de rigueur for Cocoa classes, so you’ve likely never given this much special thought. Unless, that is, you decided at some point to have two text fields on screen at once. With two text fields you need to handle two sets of callbacks. You have a couple options for how to do this:

  1. Use the same delegate to handle both sets of callbacks, and use conditionals or switch statements to differentiate between the text fields.
  2. Create UITextField subclasses for each text field, each of which knows how to handle its own events. Each subclass will need a reference to the view controller, and you’ll need to expose methods in the view controller’s public interface for the subclasses to call, in order to effect some change in the system.
  3. Create a separate delegate class for each text field. As in the previous option, each delegate class will need a reference to the view controller and a way to send it messages to effect changes in the system.

None of these options feel particularly satisfactory: the second overuses inheritance, which the delegate pattern exists largely to avoid; both the second and third can result in class explosion; and the first feels so… procedural. Isn’t Object Oriented Programming supposed to save us from problems like this?

Procedural or no, Apple suggests the first option in all of their documentation and example code. An if statement isn’t really a big deal for two text fields; but what about three? Five? Ten? Your delegate method could look something like this:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (textField == self.fooTextField) {
        if (0 == [textField.text length]) {
            return NO;
        }
        // Do something with the text
        }
    } else if (textField == self.barTextField) {
        // different logic...
    } else if (textField == self.batTextField) {
        // more different logic...
    } else if (textField == self.bazTextField) {
        // yet more different logic...
    } else if (textField == self.wibbleTextField) {
        // still yet more different logic...
    } else if ...
    [textField resignFirstResponder];
    return YES;
}

Or, alternately, you could resort to the dreaded switch statement. Either way, ugh.

The fundamental problem here is that only one object (let’s say a view controller) knows what to do when events occur, but only the subordinate objects (the text fields) know when the events occur. Each text field object encapsulates the behavior of its particular on-screen representation, but can’t access the internal state or implementation details of the view controller in order to effect changes to the system.

The recent addition of blocks to iOS can help us work around this problem. Since blocks are closures they capture and maintain their surrounding state at the point they’re instantiated. We can use this to define an implementation, and capture the internal state of our view controller, and pass all of this to an individual text field. Once done, each text field object will manage its own behavior without any intervention from the view controller whatsoever.

To make this work you’d need one (and only one) new class (theoretically, you could make a subclass of UITextField and set it to be its own delegate; unfortunately, setting a UITextField to be its own delegate seems to create an infinite loop deep in the bowels of Cocoa):

@interface BlockTextFieldDelegate : NSObject <UITextFieldDelegate>
@property (nonatomic, copy) BOOL (^textFieldShouldReturn)(UITextField *textField);
@end

@implementation BlockTextFieldDelegate
@synthesize textFieldShouldReturn = textFieldShouldReturn_;

- (void)dealloc {
    self.textFieldShouldReturn = nil;
    [super dealloc];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (self.textFieldShouldReturn) {
        return self.textFieldShouldReturn(textField);
    }
    return YES;
}

@end

Using the BlockTextFieldDelegate class might look like this (in your view controller):

- (void)viewDidLoad {
    [super viewDidLoad];
    self.textFieldDelegate.textFieldShouldReturn = ^ BOOL (UITextField *textField) {
        if (0 == [textField.text length]) {
            return NO;
        }
        [self doSomethingWithText:textField.text];
        [textField resignFirstResponder];
        return YES;
    };
}

The astute reader, armed with a passing familiarity with Apple’s Human Interface Guidelines, will point out that having several text fields on one screen may create a poor user experience. Certainly true for the iPhone, perhaps less true for the iPad’s larger screen. In any case, this technique works for any situation that requires multiple objects, not just UITextFields, reporting to a single delegate. Consider the case of multiple concurrent network requests, created by NSURLConnection objects, managed by a single view controller.

The astute reader will also point out that you may leave off the return type when defining blocks, assuming the compiler can infer it. I left the return type in to keep the example as explicit as possible, but the above block assignment could look like this (note the missing BOOL return declaration):

self.textFieldDelegate.textFieldShouldReturn = ^ (UITextField *textField) {

The block syntax isn’t beautiful, but you can use this technique to eliminate conditional chains, keep the number of classes and subclasses you create low, and avoid exposing the internal state of your objects; and that is beautiful.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

#method_missing makes me eat my words

Adam Milligan
Saturday, December 27, 2008

A while back I wrote about private methods in ActiveRecord objects, and how Rails 2.2 makes them behave as they should. ActiveRecord associations will no longer respond to private methods defined on their targets; however, my colleague Joseph pointed out that they also no longer respond to methods defined via #method_missing on their targets. Which sucks horse poop through a straw, to some extent.

In my original post I wrote this, fully aware that I was writing lies, but mostly in a rush to get on to my point at the time:

Sometimes I’m forced to use #send:

method_name = extract_method_name_from_the_aether
some_object.send(method_name)

In order to make this code correct with regard to access control I have to add cruft:

method_name = extract_method_name_from_the_aether
some_object.send(method_name) if some_object.respond_to?(method_name)

The astute reader will note that the second code block doesn’t actually approximate the behavior of calling a private method via function call syntax. It should look more like this:

method_name = extract_method_name_from_the_aether
raise NoMethodError if some_object.private_methods.include?(method_name)
some_object.send(method_name)

Two things to notice here: first, the original code didn’t throw an exception if it failed to call the method; second, and much more importantly, the set of private methods is not the complement of the set of methods an object will respond to. So, using !#respond_to? as the condition for preventing the method call is too restrictive. The fact that this code will prevent calling a non-private method defined via #method_missing clearly shows this.

Now, I know the Rails core team chose to use #respond_to? in this particular case for a good reason (which my original patch did not take into consideration): performance. Some simple investigation quickly shows that #include? is an order of magnitude slower than #respond_to? Method calls happen quite a lot, so slow is bad.

I’ve submitted another patch that should correct the #method_missing behavior without dragging everything to a halt. Building on my previous examples, the code looks something like this:

method_name = extract_method_name_from_the_aether
raise NoMethodError if !some_object.respond_to?(method_name) && some_object.private_methods.include?(method_name)
some_object.send(method_name)

Note that the conditional expression is now redundant; the first condition cannot be false if the second condition is true. However, an object will likely respond to the majority of method calls sent to it. The first conditions will (quickly) evaluate to false in these cases, short-circuiting the conditional. In the minority of cases where the first condition evaluates to true, the second condition will (slowly, but correctly) determine if the method call violates access control.

Unfortunately, sensible as it may seem, this change actually breaks has_one :through associations, because of collection-specific functionality they inherit from has_many :through associations. (Oh yes, has_one :through associations are collections, based on their place in the ActiveRecord inheritance hierarchy. Or, they were; read more about that here).

And, finally, I think it’s important to note that none of these machinations in Rails would be necessary if #send (and #send!) actually worked as it should. Heads up, Matz.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

ActiveRecord learns to respect your privates

Adam Milligan
Tuesday, December 2, 2008

This is somewhat old news, but I don’t think it has received the attention it deserves. As of Rails 2.2, ActiveRecord associations and attributes will now behave properly with regard to access control. You can view the Rails tickets, with patches, here and here.

Take, for example, this schema:

mysql> desc accounts;
+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| id             | int(11)      | NO   | PRI | NULL    | auto_increment |
| balance        | int(11)      | NO   |     | 0       |                |
+----------------+--------------+------+-----+---------+----------------+

used by this model:

class Account < ActiveRecord::Base
  def deposit(amount)
    do_state_and_federally_mandated_things
    balance += amount
  end

  def withdraw(amount)
    if sufficient_funds?(amount)
      do_state_and_federally_mandated_things
      balance -= amount
    end
  end

private :balance=

private

  def do_state_and_federally_mandated_things
    ...
  end
end

You most likely don’t want someone coming along and modifying the balance attribute directly, either intentionally or inadvertently. However, prior to Rails 2.2, ActiveRecord ignores the privacy declaration for #balance=, so you must execute horrid machinations in order to protect it:

class Account < ActiveRecord::Base
  def balance=(amount)
    raise "I'm private!"
  end

  def deposit(amount)
    do_state_and_federally_mandated_things
    write_attribute(:balance, balance + amount)
  end

  ...

As of Rails 2.2, ActiveRecord will respect private accessors for database column attributes.

Along the same vein, if we add the following:

class User < ActiveRecord::Base
  has_one :account
end

Now we can call methods on the proxy returned by calling User#account, just as if we were calling methods on an account instance; any methods:

johnny_taxpayer = User.first
johnny_taxpayer.account.withdraw(700_000_000_000)
johnny_taxpayer.account.do_state_and_federally_mandated_things

Who knows what scary things #do_state_and_federally_mandated_things does? This will, frighteningly, run just fine prior to Rails 2.2. But, no more.

Now, a number of people have considered this change and asked “why bother?” Ruby allows access to private methods via #send, so they’re not really private, right?

This argument leads down the dark path. Like it or not, cheat around it as you may, access control is an important aspect of object oriented programming. If nothing else, the private keyword is my way of saying “hic sunt dracones,” or “hands off!” It’s also a way of saying “this method may or may not exist in the future.” As a class designer I have every right to refactor that private method entirely away, thus breaking any code that calls it; including, significantly, test code.

More fundamentally, object interactions should be via interfaces. If code makes calls to an object’s private methods, that code has now tied itself to the object’s implementation. Coupling ensues, duck-typing breaks down, anarchy reigns.

So, this begs the question, why does #send ignore access control?. Why should two forms of sending a message to an object differ in their access control semantics? Sometimes I’m forced to use #send:

method_name = extract_method_name_from_the_aether
some_object.send(method_name)

In order to make this code correct with regard to access control I have to add cruft:

method_name = extract_method_name_from_the_aether
some_object.send(method_name) if some_object.respond_to?(method_name)

Now, this is not to say that I don’t think Ruby should provide the ability to call private methods, or generally dig around in an object’s internals. This comes in handy in some instances (although I find many of these instances are short-term solutions that should get refactored away). But, in an ideal world I think the sender should explicitly specify when a message should ignore access control:

potentially_private = extract_method_name_from_the_aether
some_object.send_without_restriction(potentially_private)

This makes the syntax somewhat more ugly, but ugly syntax suits an ugly operation.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (778)
  • rails (113)
  • testing (86)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (54)
  • techtalk (44)
  • rspec (38)
  • activerecord (29)
  • productivity (29)
  • gogaruco (29)
  • ironblogger (29)
  • git (28)
  • nyc (27)
  • rubymine (25)
  • mobile (22)
  • bloggerdome (20)
  • cucumber (20)
  • process (19)
  • pivotal tracker (19)
  • jasmine (19)
  • design (18)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • tracker ecosystem (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • selenium (12)
  • css (12)
  • goruco (12)
  • bundler (12)
  • tdd (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • rubygems (9)
Subscribe to access control Feed
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >