Creating a custom Key in Objective C

When creating a custom key in Objective C for NSDictionary or NSCache or the like, you need to create an object which does the following:

Implements <NSCopying> protocol.

If your key is invariant, you can implement the method copyWithZone: as follows:

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

Of course if your key is invariant, ideally you would create the key entirely using a custom init function, and mark all the properties (readonly).

Implement the isEqual: method.

This is part of the NSObject protocol. Note that any class (or nil) could be passed in as the argument to isEqual: method, so you may want to use the method isKindOfClass: to verify that you got what you expected as the parameter.

Implement the hash method.

This is also part of the NSObject protocol, and returns a NSUInteger value which provides a hash function of the data you passed in.

The hash function doesn’t need to be complicated. For example, if your key is three integers, your hash function could be as simple as:

- (NSUInteger)hash
{
    return (self.a << 8) ^ (self.b << 4) ^ self.c;
}

What is important is that two keys passed into your system are unlikely to have a similar value.

Also note that many of the classes that you see used routinely as keys (such as NSString or NSNumber) also follow this protocol. Meaning if your custom key has a string in it, you can use the NSString’s hash function as one of the inputs to your own hashing function:

- (NSUInteger)hash
{
    return (self.intVal << 16) ^ [self.stringVal hash];
}

Random thoughts.

  1. You have to write the code to understand if the algorithm is correct.
  2. There are no one-size fits all solutions, especially when it comes to design patterns. Solutions which solve most problems are general, and the more specific the solution (that is, the more restrictions placed on how the solution is to be implemented), the fewer problems that solution will solve.

Objective C subscripting operators

I keep forgetting where this link is, so I’m putting it here: CLang Reference: Objective C, Object Subscripting.

This documents the methods we need to define if we are declaring our own Objective C class and we want to implement array-style subscripting or dictionary-style subscripting.

Extracting from the text:

… Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.

Meaning if the compiler detects the subscript is an integral type, it uses the array-style subscript method calls, and when the subscript is an Objective C pointer type, it uses a dictionary-style subscript method call.

For array subscripting, use either or both of the methods

- (id<NSObject>)objectAtIndexedSubscript:(NSInteger)index;
- (void)setObject:(id<NSObject>)value atIndexedSubscript:(NSInteger)index;

For dictionary-style subscripting, use either or both of the methods

- (id<NSObject>)objectForKeyedSubscript:(id<NSObject>)key;
- (void)setObject:(id<NSObject>)value forKeyedSubscript:(id<NSObject>)key;

This goes hand-in-hand with my earlier post Objective C declaration shortcuts, and has been a public service announcement.

Moving views around when the keyboard shows in iOS

When the keyboard shows or hides in iOS, we receive an event to notify us that the keyboard is being shown and being hidden.

Ideally we want to get the animation parameters and the size of that keyboard so we can rearrange the views inside of our application to fit the keyboard. I’m only covering the case of the keyboard on the iPhone; on the iPad you also have the problem of the split keyboard, but the same ideas should hold there as well.

Step 1:

When the view controller that may show a keyboard appears, register for notifications for the keyboard being shown and hidden:

- (void)viewDidLoad
{
    [super viewDidLoad];

	// Do any additional setup after loading the view.
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardShowHide:) name:UIKeyboardWillShowNotification object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardShowHide:) name:UIKeyboardWillHideNotification object:nil];

	// other stuff here
}

Step 2:

Remember to unregister notifications when this goes away, to prevent problems.

- (void)dealloc
{
	[[NSNotificationCenter defaultCenter] removeObserver:self];
}

Step 3:

Receive the event in our new method, and extract the keyboard parameters and animation parameters.

- (void)keyboardShowHide:(NSNotification *)n
{
	CGRect krect;

	/* Extract the size of the keyboard when the animation stops */
	krect = [n.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

	/* Convert that to the rectangle in our primary view. Note the raw
	 * keyboard size from above is in the window's frame, which could be
	 * turned on its side.
	 */
	krect = [self.view convertRect:krect fromView:nil];

	/* Get the animation duration, and animation curve */
	NSTimeInterval duration = [[n.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
	UIViewAnimationCurve curve = [[n.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];

	/* Kick off the animation. What you do with the keyboard size is up to you */
	[UIView animateWithDuration:0 delay:duration options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
			/* Set up the destination rectangle sizes given the keyboard size */
			Do something interesting here
		} completion:^(BOOL finished) {
			/* Finish up here */
			Do something interesting here
		}];
}

Basic Lessons: Object Oriented Programming with Objects

The really stupid thing, by the way, about most code that I review is how few people know about object oriented development. Yes, yes, yes; they say they know all about object oriented development–but when you then review their code (say, in an iOS application with a table) do they practice proper encapsulation? Nooooooooooo…

All too often I see something like this:

MyTableViewCell.h

@interface MyTableViewCell: UITableViewCell
@property (strong) IBOutlet UILabel *leftLabel;
@property (strong) IBOutlet UILabel *rightLabel;
@end

MyTableViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCell *c = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell" forIndexPath:indexPath];

    c.leftLabel.text = [NSString stringWithFormat:@"Left %d",indexPath.row];
    c.rightLabel.text = @"Right Label";

    return c;
}

The text in red above: no, no, no, no, no.

Haven’t you even heard of encapsulation? No? Well, that’s probably because (a) most developers have no idea what they’re doing beyond copying someone else’s models, and (b) they’ve been taught some bad habits by other developers who also have no idea what they’re doing.

Of course this isn’t helped by Apple, whose own UITableViewCell by default exposes the fields contained within.


What is object encapsulation?

The idea of object encapsulation is central to the idea of object oriented programming. Essentially it refers to the idea of creating “objects”–chunks of data associated with functions designed to work on that data.

To understand how useful this is we need to dive into a pre-OOP language, such as C.

Back in the “bad old days” of C, you had functions, and you had structures. And that was it:

struct MyRecord
{
    int a;
    int b;
};

int AddFields(struct MyRecord x)
{
    return x.a + x.b;
}

While this sort of procedural programming has it’s place–and languages such as C are extremely good at embedded development or in Kernel programming (where execution efficiency is important), it falls short with developing user interfaces, simply because with user interfaces we manipulate things like buttons and text fields and table view cells.

In fact, it turns out that object-oriented programming is tied to user interface development, by abstracting the idea of user interface elements into a new concept of an “object” as a self-contained unit that combines the idea of a structure or record with the idea of functions or procedures that operate on that record.

In C++, we can express this idea as a class:

class MyRecord
{
	int a;
	int b;

	int AddFields();
};


int MyRecord::AddFields()
{
	return a + b;
}

Notice that this expresses the same idea as our C snippet above, which adds the contents of the two fields in MyRecord. Except now, AddFields is associated with a record. This means if we have a record and we want the sum of the fields, instead of writing

MyRecord a;
int sum = AddFields(a);

we write

MyRecord a;
int sum = a.AddFields();

That is, we apply the message against the object.

Now we haven’t really done anything new yet. In fact, if you were to write in C++ the method ‘AddFields()’ from our C example, it would still work with our C++ declaration of MyRecord.

But C++ gives us a new tool: a way of marking fields “private”–that is, only accessible from the methods that are associated with the class.

Thus:

class MyRecord
{
	private:
		int a;
		int b;

	public:
		int AddFields();
};

We’ve hidden a and b from view. Now the only way you can change a and b or get their values is through methods which are then made public with MyRecord.

Encapsulation is the process of creating self-contained objects: objects which provide a clear interface for manipulating the object, but which hide the details as to how the object does it’s work.

Now there was no need to actually use the new features of C++ to provide this sort of data hiding. In C, we can take advantage of the fact that things declared within a single C file stay within that file: we could declare a pointer to a structure in our header file, but hide the details by declaring them in the C file that contains the implementation. C++ makes this easier for us by giving us better tools to manipulate access to the contents of the object.


Why is encapsulation important?

Simply put, encapsulation allows us to separate the “what” from the “how”; separate what we want an object to do from how the object actually does the work.

This becomes important for two reasons.

First, it means that we have an object which has a clearly defined “purpose.” For example we can define an object which represents a button on the screen: a rectangular region the user can tap on or click with their mouse, which then responds to that tap by visually changing appearance and by firing an event which represents the response to that tap or button press.

And second, tied to the first, we can isolate all of the code which handles the button’s behavior within the button itself. A user of the button doesn’t need to know the details of how a button works to put one on the screen, nor does the user need to know how a button receives click or tap events, or how it processes those events. A user doesn’t even need to know the details of how a button draws itself: they don’t need to know how the button handles details such as switching text alignment for languages which read right to left instead of left to right.

And because the details are isolated away, it means those details can change: instead of firing an event on the down click of the mouse the event can be fired when the mouse click is released. The button’s appearance can change–or even be changeable depending on the skin the user selects. The button can even be handled as a spectrum of button-like objects. None of this matter to the user of that button: drop one on the screen, set the text, and wire up the event for the response, and you’re done.


How we can change our object above to respect proper encapsulation

This idea of encapsulation is one that we can–and should follow in our own code. That way if we later have to change the details of how we implement a thing, it doesn’t require us to hunt through all of our code and change the details everywhere else. Change the object, not all the callers manipulating the object.

So, for our UITableViewCell example above, the change is simple. First, hide the details how our table view cell is implemented:

MyTableViewCell.h

@interface MyTableViewCell: UITableViewCell
- (void)setLeftText:(NSString *)left rightText:(NSString *)right;
@end

MyTableViewCell.m

@implementation MyTableViewCell
@property (strong) IBOutlet UILabel *leftLabel;
@property (strong) IBOutlet UILabel *rightLabel;

- (void)setLeftText:(NSString *)left rightText:(NSString *)right
{
    self.leftLabel.text = left;
    self.rightLabel.text = right;
}
@end

And in our caller code:

MyTableViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCell *c = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCell" forIndexPath:indexPath];

    c.leftLabel.text = [NSString stringWithFormat:@"Left %d",indexPath.row];
    c.rightLabel.text = @"Right Label";
    [c setLeftText:[NSString stringWithFormat:@"Left %d",indexPath.row]
         rightText:@"Right Label"];
 

    return c;
}

The original offending code was wrong because it confused the “how” to do something (setting the internal structure of the table cell) with the “what”: set the left and right text.

And notice that now we’ve hidden the details inside the table view. So later, if for some reason we change our implementation of the UITableViewCell:

MyTableViewCell.m

@implementation MyTableViewCell
@property (copy) NSString *leftLabel;
@property (copy) NSString UILabel *rightLabel;

- (void)setLeftText:(NSString *)left rightText:(NSString *)right
{
    self.leftLabel = left;
    self.rightLabel = right;
	[self setNeedsDisplay];
}

- (void)drawRect:(CGRect)r
{
    CGRect textRect = CGRectMake(10, 0, 146, 44);
    {
        NSString* textContent = self.leftLabel;
        UIFont* textFont = [UIFont fontWithName: @"HelveticaNeue-Light" size: UIFont.labelFontSize];
        [UIColor.blackColor setFill];
        [textContent drawInRect: CGRectOffset(textRect, 0, (CGRectGetHeight(textRect) - [textContent sizeWithFont: textFont constrainedToSize: textRect.size lineBreakMode: UILineBreakModeWordWrap].height) / 2) withFont: textFont lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentLeft];
    }

    CGRect text2Rect = CGRectMake(164, 0, 146, 44);
    {
        NSString* textContent = self.rightLabel;
        UIFont* text2Font = [UIFont fontWithName: @"HelveticaNeue-Light" size: UIFont.labelFontSize];
        [UIColor.blueColor setFill];
        [textContent drawInRect: CGRectOffset(text2Rect, 0, (CGRectGetHeight(text2Rect) - [textContent sizeWithFont: text2Font constrainedToSize: text2Rect.size lineBreakMode: UILineBreakModeWordWrap].height) / 2) withFont: text2Font lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentRight];
    }
}
@end

Notice that we don’t have to change a single thing in MyTableViewController.m, simply because it never knew how the table view drew itself; it only knew how to ask.

Wrapping text with ellipsis on iOS

This is an extremely common pattern I encounter quite a few times, and worthy of it’s own “things to remember” post.

So you want to have some text which wraps, but when it hits the bottom of the window, you get an ellipsis, right? But [NSString drawInRect…] doesn’t do the trick, right?

Well, it turns out the answer is using an NSAttributedString.

The first step is to turn your label string into an attributed string. At this point you need to know the font and color of the text that will be rendered, so you need to bake these attributes into the string. So, for example:

- (NSAttributedString *)attributedStringWithString:(NSString *)str
{
	UIFont *font = [UIFont boldSystemFontWithSize:19]; /* Some font */
	UIColor *color = [UIColor blackColor]; /* Some color */
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
		font, NSFontAttributeName,
		color, NSForegroundColorAttributeName,
		nil];
	return [[NSAttributedString alloc] initWithString:str attributes:d];
}

The next step is to draw the string in the rectangle area where it belongs:

	NSAttributedString *astr = [self attributedStringWithString:self.myLabel];
	[astr drawWithRect:r
		options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
		context:nil];

And this will wrap the text, truncating the last line with an ellipsis.


The advantage of using NSAttributedString is that you can also easily insert segments of text which are of a different color or style. I find it easiest to build up the attributed string through concatenation of attributed segments into an NSMutableAttributedString object. So, for example, if you’re displaying a tweet from Twitter and you wish to bold all the hashtags, you simply parse the string (scanning for sequences staring with whitespace and a ‘#’, and including all the alphanumeric characters past the ‘#’), and create an attributed string of that segment as bold, concatenating all the strings into a single mutable string.

And for optimization purposes you can then hang onto the attributed string rather than the original string.