Website Logo. Upload to /source/logo.png ; disable in /source/_includes/logo.html

Hacker School Log

Laura Skelton | Summer 2014 Batch

Hacker School Day 17: Objective-C Particulars and Conceptual Limits

I learned a bunch of little things about Objective-C today in the course of trying to write good tests for my Secret Handshake app.

After running into a bunch of unhelpful compiler errors, like Member reference type 'struct_objc_class *' is a pointer, I finally figured out the difference between a + and a - in an Objective-C method.

A + at the front of an Objective-C method indicates that it is a Class Method. That means that you don’t need to call that method on a particular instance of the class- you can call it without ever having instantiated the class. For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+ (NSDictionary *)parseQueryString:(NSString *)query
{
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:6];
    NSArray *pairs = [query componentsSeparatedByString:@"&"];

    for (NSString *pair in pairs) {
        NSArray *elements = [pair componentsSeparatedByString:@"="];
        if ([elements count] == 2) {
            NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            [dict setObject:val forKey:key];
            key = nil;
            val = nil;
        }
        elements = nil;
    }
    pairs = nil;
    return dict;
}

I don’t have to instantiate my QueryParser class in order to call this parseQueryString: method to parse a query string into a dictionary. Because the class instance doesn’t need to exist for this method to be called, I’m not allowed to use a reference to self or self.someproperty within a class + method, and it will throw a confusing compiler error if I try to do this. Because I normally use methods that operate on a particular class instance, I rarely use + methods. The parseQueryString: method doesn’t necessarily need a + if I throw it into another class that might need to parse query strings. It only needs the + if I want it to be more modular, and put it into a convenient file full of self-contained methods I might use in many other classes, where it wouldn’t make sense to instantiate some unused object on which to call the method before parsing my string.

I do absolutely need to use the plus when I’m creating a class that’s a singleton. For example,

1
2
3
4
5
6
7
8
9
10
11
+ (OAuthHandler *)sharedHandler
{
    static OAuthHandler *_sharedHandler = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedHandler = [[OAuthHandler alloc] init];

    });

    return _sharedHandler;
}

Outside of the OAuthHandler class, I refer to [OAuthHandler sharedHandler], which will either create a single shared instance of the OAuthHandler class for my app, or will return the already-created instance of OAuthHandler. This is a convenient way for me to have one OAuthHandler referenced by several other classes without complicated dependencies. Because the sharedHandler method actually creates the OAuthHandler class instance, it can’t be called on an instance I already have a reference to, so it needs to have a +.

For most other types of methods I’d use in Objective-C, it makes sense to use a -. When I need to run a method that references the specific properties of that instance of the class, I need to use the - type of method. For example, I would use a - method if I needed to configure a view with a specific state.

1
2
3
4
5
6
7
8
9
- (void)configureView {
    // Update the user interface for the detail item.
    if (self.event) {
        self.nameLabel.text = [NSString stringWithFormat:@"%@ %@",self.event.hackerSchooler.first_name, self.event.hackerSchooler.last_name];
        self.batchLabel.text = self.event.hackerSchooler.batch;
        self.profileImageView.image = [UIImage imageWithContentsOfFile:self.event.hackerSchooler.photoFilePath];

    }
}

Because I need to access this particular view controller instance’s properties, such as self.event.hackerSchooler, in order to display this particular person’s name and photo, I must use the - to indicate that this is an Instance Method, and not a Class Method that could be called without a class instance that has specific property settings.

I also learned the difference between a * and a & in Objective-C, and a little bit about how pointers work. Whenever I name an object in Objective-C, I write something like NSString *someString. This * indicates that someString is a pointer to an NSString type object. If I create two strings and try to directly compare their pointers, it will only return true if the pointers are pointing to the exact same instance of the object at the same memory location.

1
2
3
4
5
NSString *firstStringPointer = @"hello world";
NSString *secondStringPointer = @"hello world";
if (firstStringPointer == secondStringPointer) {
  return YES;
}

This string pointer comparison will return false, even though the strings are identical, because they are two different string objects. It’s like, we are checking if two people are the same person, and these two string pointers are the names of identical twins instead of nicknames for the same person, so it will answer that No, this is not the same person, even though the two people are identical.

1
2
3
if ([firstStringPointer isEqualToString:secondStringPointer]) {
  return YES;
}

That’s why we have to use the above type of comparison method if we want to check if two objects have identical properties, instead of whether they are the exact same instance of the object, which is asking a fundamentally different question. Like asking about the identical twins, do these people look exactly the same, and have all of the same features? Yes, they do.

The & I only use when I’m declaring an error that I pass to a method which might or might not return an error. I don’t instantiate the error, but I use the & to create a reference to a location in memory where an NSError object might be put in the future, if the method needs to do so.

1
2
3
4
NSError *error;
  if (![self.fetchedResultsController performFetch:&error]) {
      NSLog(@"Unresolved error: %@", error);
  }

As I understand it, if the performFetch method fails, it will create an NSError object and place it at the memory location referenced by &error. I can subsequently access the NSError object by using the error pointer. If it succeeds, then error is nil.

I also enjoyed reading rntz’s post about Option and Null in dynamic languages. I had some trouble following the explanations in Haskell, as I’m unfamiliar both with the syntax and with the concepts in Haskell that don’t exist in Objective-C.

Ironically, this is part of the point rntz was trying to make (in Appendix A) about how different programming languages can limit the way you conceive of the world, similarly to how native speakers of a language that conflates the colors Blue and Green have trouble visually differentiating the two colors, since their language only creates one cognitive category for the two.

After Anatoly explained a few things about Haskell syntax, as well as the Maybe datatype, which seems to work similarly to ? Optionals in Swift, I followed the explanation a lot better, and it was interesting to recognize that because of the way Objective-C dictionaries are structured, I conceptually conflate a key being set to nil as being the same as a key not being in the dictionary at all, (actually, the way to check in an NSDictionary if a key exists is to see if [dictionary objectForKey:@"someKey"] is nil) and how this could be seen as actually two distinct ideas: One, that the key does exist, but it is nil, and two, that the key does not exist in the dictionary.

The congnitive limits that can come about through the limitations of whichever programming language in which you first reach fluency is something I’ve been struggling with as I’m learning Swift after working within the confines of Objective-C for so long. I can simply translate the way I’ve implemented something in Objective-C into the new syntax that Swift introduces, but this severely limits my ability to take advantage of much more precise and efficient tools that Swift has with which I’m completely unfamiliar. I’m excited about getting better at native Swift tools as I can see this expanding the way I conceptualize code, which would give me tools to be a better programmer in the future in many other languages more powerful than Objective-C.