Jaanus

Musings on my life and work.

How to Correctly Configure Building Private OS X Frameworks

I’ve been recently dealing with building a private / embeddable framework on OS X. By “private framework”, I mean a framework that’s not installed system-wide, but one that’s bundled with an OS X application. Now that frameworks are also coming to iOS, it’s probably of wider interest, although this specific post is only about OS X. I spent several hours yesterday trying to get it to work, and thought to just document it, so that I wouldn’t forget myself.

TL;DR version: you need to change some build settings to the following values:

Skip Install = YES
Installation Directory = @executable_path/../Frameworks

You also need to add a “Copy files” build phase to your application target to copy the framework into its “Frameworks” group. And you also need to think about code signing, which I’m not covering here.

Okay. That was the summary. Below is an exploration of my adventures. And grab the example project.

The test project

I created a test project with Xcode 5.1.1, consisting of the default Cocoa application target. I then added a Cocoa Framework target with default settings. My test app is called HelloFramework, and the framework is simply called Hello. The code for the framework is very simple, here’s the header.

1
2
3
4
5
6
7
@interface Hello : NSObject

+ (void)helloFromClass;
+ (instancetype)sharedHello;
- (void)helloFromInstance;

@end

And the implementations imports the framework: #import <Hello/Hello.h> and just show some modal dialog boxes a la good old Javascript alerts.

Okay, so far, so good. We add the Hello framework to our app target in “Link Binary with Libraries” phase. We add a new “Copy Files” phase to bundle the framework into the application. We run it in Xcode, and everything looks good. Dialog boxes come up.

Now, things start to get a bit weird.

Archiving trouble

Let’s archive the app target. The first sign of trouble is that the archive is not of type “Mac App Archive” as expected for the Mac app, but is of type “Generic Xcode Archive”, which most of the time in Xcode means “Probably Not What You Want”. But okay. Let’s try distributing it. I only have the choice of “Save Built Products” instead of exporting the app for distribution. Let’s do this anyway.

Here’s what’s exported.

So there’s both the application and the framework. But we don’t need the framework; we just want the application. If we peek inside the app bundle, we even see that is has a correct Frameworks group with the Hello.framework nicely sitting in there.

Well, let’s try to run the app. BOOM, it crashes.

What the what? Well, if we look at the error, it says right there what the problem is.

1
2
3
4
Dyld Error Message:
  Library not loaded: /Library/Frameworks/Hello.framework/Versions/A/Hello
  Referenced from: /Users/USER/Desktop/*/HelloFramework.app/Contents/MacOS/HelloFramework
  Reason: image not found

Okay, so it’s trying to load the library from a global path. Why is that?

System vs private frameworks

There’s two kinds of frameworks. The system ones go in /Library/Frameworks, and can be used by multiple applications. The default Cocoa Framework template seems to be set up for building these. I’m not sure what their future is, though, since a lot of app distribution happens through Mac App Store and these apps are sandboxed and I don’t think they can install system frameworks.

The other kind of frameworks, private frameworks, are the ones that are embedded in the actual app bundles. These are what we’re trying to build, and are failing so far in the example.

Turns out that the install location of a framework is part of its build settings. When we look at the Installation Directory of our framework target, it is by default, unsurprisingly, set to $(LOCAL_LIBRARY_DIR)/Frameworks, which resolves to /Library/Frameworks on my system. This is not what we want. We want the framework to be embeddable in apps, and so the installation path should be relative to the app that contains the framework.

What’s the right value? I found this post to be useful when working through this topic, but they recommend changing a bunch of values that don’t seem to be necessary. I found the official doc which says, hidden inside all the other wisdom, that the Installation Directory for private frameworks should be @executable_path/../Frameworks, which looks pretty reasonable.

Great! Let’s change the installation path. When we now archive our app, we see that it creates “Mac App Archive” as expected, we can run it, and it no longer crashes. Fantastic.

There’s a warning when archiving the app target, though. Let’s get rid of that.

Fixing the last warning

The warning says:

1
Warning: Installation Directory starts with '@executable_path' but Skip Install is disabled.

It’s not super clear, but it’s clear enough if you’ve dealt with iOS app archiving troubles before and are familiar with Skip Install build setting. Basically, for a given target, Skip Install says (in the negative) whether it’s an installable target or not, which roughly translates to “Is this the app that the user will run” (in my mind, anyway). Why it needs to do that in the negative, I don’t know, calling it “Installable” would be much clearer. But just negate it in your head and it makes sense.

Skip Install = NO makes sense for system frameworks. You do want them to be installable. Although how that actually works beyond them being exported when archiving, I don’t know exactly. Anyway, in our case, for our private framework, we don’t need it to be installable so we set it to YES, and boom, the warning goes away.

The one thing to note is that there’s no nice way to archive the framework now, since it’s not an installable target. If we want to use it in another app as a pre-built thing, I just build it in Xcode and then grab the build result from the build products folder on the disk, probably with Release configuration if it’s meant to be used by others.

The mysteries remain

A few more things to note.

How is a normal person supposed to find and gather this info? I spent a few hours googling and trying out random stuff, as I wasn’t too familiar with frameworks, before I converged on this info. I think it could be a lot cleaner.

Why did the framework with wrong installation settings work when I was running the app in Xcode, and crash after exporting and trying to run the same app outside Xcode? I guess Xcode tries to be helpful here, when the framework project is part of your app workspace, and somehow masks out all these installation problems. But I think it was harmful in this case, because it really obscures the problem and shows there’s no substitute for testing the exported end product. Some of Xcode’s ways remain mysterious to me.

How does all this interact with code signing, and how will this work with Xcode 6 and iOS 8 where frameworks are now also supported? I don’t know enough about these topics right now to cover them myself, but maybe I’ll do a follow-up once I drill down into that.

Anyway, you can grab my example project here.

xScope 4 Breaks How Loupe and Guides Work Together

I do a lot of precise UI layout work. This means that I must be able to measure miscellaneous forms of comps, prototypes, and layouts. xScope has been an indispensable tool in doing this, but the latest version, xScope 4, breaks a particular behavior, that I thought might be useful to document here, so that you could also consider this when buying the upgrade.

I often use Guides and Loupe together. I position the Loupe into a particular position, and then move the Guides in for precise measurements. The magnified guides show up with the rest of the content while I make pixel-precise adjustments to the Guide positions.

For example, in the above workflow, I used the Loupe and Guides together this way, to determine that the spacing between baselines of two lines of text in OS X System Preferences, a.k.a the line height, is 28 pixels, or 14 points, since this was captured on a Retina display. (And xScope 4 lets you toggle between pixels and points in this case, which is great.)

The important point to note above is that in the z-ordering of tools, Loupe is always positioned above Guides, so it shows the magnified guides together with the content, which is absolutely my desired behavior.

The z-ordering of tools has changed in xScope 4. Sometimes, xScope 4 looks like above. And sometimes, it looks like this.

This latter look is useless for me because the guides don’t relate to anything.

See, the z-ordering of tools in xScope 4 is based on which tool is currently active. If you interact with the Loupe, it is above guides, and looks correct. But as soon as you try to start moving the guides, the guides are moved above the Loupe, and it looks incorrect.

This is a deal breaker for me and makes xScope quite useless, so much so that I have to keep using the previous version.

I have contacted xScope support team who essentially confirmed that the above description of the behavior is indeed correct. I don’t yet have an answer about whether this change in xScope 4 is a bug or a feature, or what’s next with this.

I hope that they change xScope 4 to make it possible for me to keep using it like this, with Loupe always above Guides. One way to think about it is that Loupe is a meta-tool that should magnify the output of all the other tools along with the content. I don’t want to use the guides to examine Loupe UI: I want to use them to examine the same magnified content that I am looking at with the Loupe.

I don’t care how exactly they fix it: whether they make this a preference, or default behavior, or I must do some sort of hack (change NSDefaults or whatever) to go back to the previous behavior. I just hope that there will be a way to do this. I will update this post when I get more info about this change.


By the way, if you made it this far, I’m still looking for people for closed beta of my new thing. Check it out and contact me if interested.

Why NSNotificationCenter Sometimes Deadlocks When Trying to Deliver Notifications

I’m working on something that involves some multi-threading with Grand Central Dispatch and multiple queues. Always a fun topic and a can of worms. Today, I hit a bug around this area that made me pause and think for a bit. I’m happy with myself that I was able to reason through the situation, and thought I’d post the writeup.

I’m synchronizing access to a resource using a particular serial queue. Any thread or queue posts stuff it wants to do with the resource on this queue, and it’s nicely serialized.

At one point, though, I hit a deadlock with NSNotificationCenter. Multiple queues were seemingly waiting on the lock, and the synchronization queue was blocked on posting a NSNotification. Wait, what?

When I was less experienced, these kinds of concurrency bugs used to freak me out and I didn’t really know what to do. I’d try random things and hope it worked, and sometimes it did, but I never used to develop a conclusive solution and explanation. But I guess I‘ve been doing this for a while now, and today I was able to resolve this with hypothesis-driven methodic approach. So let’s drill down. In the end, it was actually quite an easy fix. Silly, even.

One of the things that the serial queue does is post a notification about something that changed. The queue doesn’t redirect this posting anywhere else, i.e it ends up being posted on the same queue. But the posting call was blocked.

Well, let’s look at who’s consuming the notification. The only consumer was in a view controller:

1
2
3
4
5
6
someObserver = [[NSNotificationCenter defaultCenter] addObserverForName:notificationName
  object:nil
  queue:[NSOperationQueue mainQueue]
  usingBlock:^(NSNotification *note) {
      [weakSelf doSomethingInUi];
  }];

What’s going on in the main queue? The debugger shows that it is waiting to post some code in the same serial queue who’s trying to post the notification. From here on, it was easy.

So, the situation was that the serial queue was trying to post something on the main queue, while the main queue was blocked trying to post in the serial queue, and wouldn’t accept the notification. Classic deadlock.

Breaking the deadlock is easy. The technique of having notifications delivered on the main queue with the above API is usually useful, because it means you don’t have to redirect the execution yourself to another queue, but in this case it is hurting us, because the main queue may be blocked. So we’ll need to do a bit of manual legwork to more directly redirect the execution.

Also, from a requirements perspective, since the effect of the notification is that it shows some feedback to the user in the UI, it doesn’t have to execute instantly, together with the actual change. Well, it has to be fast enough for the user to perceive it as instant, but it definitely doesn’t have to happen during the same runloop.

So, let’s put the pieces together and fix the notification consumer.

1
2
3
4
5
6
7
8
someObserver = [[NSNotificationCenter defaultCenter] addObserverForName:notificationName
  object:nil
  queue:nil
  usingBlock:^(NSNotification *note) {
      dispatch_async(dispatch_get_main_queue(), ^{
          [weakSelf doSomethingInUi]; 
      });
  }];

Using nil for queue means “use whatever queue is sending this notification”, which in my case was the serial synchronization queue. And we then schedule the callback code ourselves to be execute asynchronously.

And voila, the main queue is not blocked any more and this worked fine.

My New Thing, and How You Can Help Me Make It

I’m working on a new thing.

It will be a tool for designers and developers to work better, together.

I’ve worked in the technology industry and specifically in designing and building websites, apps and UI-s for, gosh, around 15 years now. As I’ve been in different organizations, I’ve noticed some repeating trends and bottlenecks around tooling and also, more importantly, about people and how they work together. Or, how the workflow could sometimes be more fun and collaborative with better tooling.

Many organizations have by now realized that as technology becomes more and more powerful, everyone is on a more level playing field when it comes to making things. Technology and engineering, while still important, are no longer the limiting factors. Instead, you can stand out from the crowd with better design and user experience.

Yet, as a designer, you still are limited by the engineers who will build the thing for you. Some people seem to think that the answer is to have unicorns: people who can do both amazing design and then build the thing themselves. There are some people like that. If you are one of those people and can do both sides equally well, then I have nothing to teach you. You can do whatever you want. You have accomplished nirvana. Go forth and make things. You, my friend, are free.

For the rest of us, though, we still build things as designers and engineers, and need to work well together while operating with different mindsets and tools. We are united by common goals, yet sometimes have different or conflicting ideas about how to achieve those, when it comes to delivering polished apps. I am working on a tool to help make this collaboration smoother, more efficient and satisfying for all involved parties.

So, where do you come in?

I will have a closed beta period for at least several months. I want the tool to be great when it is published. There still are many hypotheses to test, and loose ends to tie up, and UI to polish, before it’s ready for a wider audience.

I am looking for users for my closed beta period, who are willing to think along and try this thing out. Here’s what I’m looking for:

  • You are working on an iOS or Mac app. Both new (not yet shipped) and existing apps (already shipped, now working on updates/next versions) are fine.
  • You have at least one designer and one developer on your team, with both of these roles fairly loosely defined. (“Designer” can be “visual”, “interaction” or whatever else your term is.) The tool is also useful for one-man builders, but I believe it will shine in teams, and that’s what I want to try out.
  • Ideally, you are based in Europe because that’s where I am, and it is easier for me to get around here. Possibly some time during the process, I would like to visit you to learn more about your team, processes, and see how the tool fits in to how you work, as well as help you get started in person. Doesn’t matter where exactly in Europe you are as long as it’s reasonably reachable by plane.

The technology is coming well together, but the project is still in its early stages, so you should be prepared to put up with the usual annoyances of early alpha-style software, like things not working, API-s breaking or changing without proper processes etc.

In return for your time, I can hopefully give you a better development process and a glimpse at how apps will be refined in the future.

If the above sounds interesting to you, then please do get in touch with me.

I will also be at WWDC in San Francisco next week so feel free to also ping or grab me to talk more in person, if you’re around SF during this time.

Far Cry 3: An Excellent Sandbox Shooter. 10/10

I recently finished the single-player campaign of Far Cry 3. According to Steam, it took me 53 hours.

Wait, what?

Yes. 53 hours.

That’s a huge amount of time to spend on a single-player game. Something like 10 hours might be more typical in my experience.

But, FC3 did take 53 hours over many calendar months. I only played a few hours at a time. And to its credit, not a single moment of it felt like wasted time, too repetitive or boring or some such. It really is a great game. I’ve recently reviewed too many “meh” games here, that I would much rather not replay. But FC3 is one that I truly do recommend if you are a fan of open-air sandbox shooters.

Here’s a video to kick it off, that shows you the highlights of the game.

Now, I’ve played the previous version before. Here’s my review of Far Cry 2. The two main gripes that I had with FC2 were that you can never really secure an area of the map, and the long time it takes to travel between regions. In FC3, both of them have been definitively fixed. When you liberate parts of the island, they are liberated for good. And fast-traveling to previous known locations is as simple as opening the map and double-clicking.

Story-wise, there is no connection to the previous parts of the series. Gameplay-wise though, this feels very much like Far Cry 2 with all of its problems fixed.

When you start to play the game, it can seem overwhelming at first. You need to acquire weapons. You need to craft some syringes. There’s so much to do! Should I follow the stories or side quests?

I can only say, relax and enjoy, because that’s what I did to gain my 50+ hours of gameplay. I did do all the side missions and explored the island. I can recommend that you try to max out on your weapons and gear before proceeding with the story quests, because it then becomes more fun and enjoyable.

How to Add a Custom Separator Supplementary View to UICollectionView

I ran into something recently that I thought might be interesting to post, since I did not see a similar example online: adding custom supplementary views to UICollectionView.

I needed to add a separator in a particular spot between the items within one section. Now, you might do this with collection view sections instead of a custom supplementary separator view. But suppose that you don’t want to re-partition your data into sections, and are just getting a flat array from upstream, and just want to work with that one.

So, without further ado, here’s what it looks like. The code is on Github if you just want to grab it. I’ll discuss some implementation details below.

Limitations

This approach has a few limitations.

  • Only one separator is supported at a time. It wouldn’t be hard to add multiple ones, but the math would be a bit more involved, and I don’t want to overcomplicate the example.
  • Only one-column layout is supported. So in a sense, you could do the same with UITableView, except that UITableView does not have such nice concept of custom supplementary views.
  • Only vertical direction is supported. It would be straightforward to make this work with horizontal scrolling as well, just switching some opeations from y/height to x/width, but it’s outside the scope of the example.

The core idea

When I was more junior and didn’t know any better, I would do horrible things when having to do something like this. Perhaps make the separator part of some cell, or, god forbid, have a custom view floating on top of the table or collection, and scroll it when the rest of content gets scrolled.

Now, though, things are different. UICollectionView and its FlowLayout do most of the heavy lifting for us, and have convenient hooks where we can customize the behavior as we want.

So, we’ll let the FlowLayout work as usual, and then, if a separator is present, just shift the items below the separator down, and draw the separator as a custom supplementary view type. FlowLayout knows only about “header” and “footer” supplementary views, but there’s no contract saying that we can’t have additional custom supplementary views in addition to these, so we do exactly that.

So let’s get started and implement this.

Register the custom supplementary view.

We don’t need a subclass or anything (although we could), we just register the ReusableView class, and handle its layout inline in the controller.

1
2
3
4
5
6
7
8
9
10
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

  // Register the separator class.
  [self.collectionView registerClass:[UICollectionReusableView class]
          forSupplementaryViewOfKind:SeparatorViewKind
                 withReuseIdentifier:@"Separator"];
}

Drawing the custom separator

After everything has been created correctly, the controller eventually gets a call to draw and configure the separator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
  UICollectionReusableView *separator = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:separatorReuseIdentifier forIndexPath:indexPath];

  if ([kind isEqualToString:SeparatorViewKind]) {
      separator.backgroundColor = [UIColor clearColor];

      if (!separator.subviews.count) {

      // … create the subview to represent the line, and set it up
      // if subviews were present, it means this work has already been done

      }
  }

  return separator;
}

The layout object

We’ll need a subclass of FlowLayout that also has some custom delegate methods, since it needs to know about where to draw the separator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@protocol JKSeparatorLayoutDelegate <NSObject>

/// Index path above which the separator should be shown, or nil if no separator is present.
- (NSIndexPath *)indexPathForSeparator;

/// Check for index path validity, since layout math doesn’t know about the model.
- (BOOL)isValidIndexPathForItem:(NSIndexPath *)indexPath;

@end



@interface JKSeparatorLayout : UICollectionViewFlowLayout

@property (nonatomic, weak) IBOutlet id<JKSeparatorLayoutDelegate> separatorLayoutDelegate;

@end

Content size

We need to return the correct content size. If we don’t do this, everything else will work correctly, but some items will be out of the view and you can’t scroll to them, you just see them when rubberbanding at the end.

1
2
3
4
5
6
7
8
9
- (CGSize)collectionViewContentSize
{
  // Increase the content size by separator height, if one is present
  CGSize s = [super collectionViewContentSize];
  if ([self.separatorLayoutDelegate indexPathForSeparator]) {
      s.height += separatorHeight;
  }
  return s;
}

The element shifting

The real work of the layout happens in the method - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect. We get a call to it with the rect that is going to screen. We can just shift the elements below the separator down here, and also add layout attributes for the separator itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
  // Grab computed attributes from parent
  NSMutableArray *attributes = [NSMutableArray arrayWithArray:[super layoutAttributesForElementsInRect:rect]];

  // Possible attributes for separator
  UICollectionViewLayoutAttributes *separatorAttributes = nil;

  for (UICollectionViewLayoutAttributes *attr in attributes) {

      // If there should be a separator above this item, then create its layout attributes
      if ([attr.indexPath compare:[self.separatorLayoutDelegate indexPathForSeparator]] == NSOrderedSame) {
          separatorAttributes = [self layoutAttributesForSupplementaryViewOfKind:SeparatorViewKind atIndexPath:attr.indexPath];

            CGRect separatorFrame = attr.frame;
            separatorFrame.size.height = separatorHeight;
            separatorAttributes.frame = separatorFrame;

      }

      attr.frame = [self adjustedFrameForAttributes:attr];

  }

  if (separatorAttributes) {
      [attributes addObject:separatorAttributes];
  }

  return attributes;
}

- (CGRect)adjustedFrameForAttributes:(UICollectionViewLayoutAttributes *)attributes
{
  CGRect f = attributes.frame;
  NSIndexPath *separatorIndexPath = [self.separatorLayoutDelegate indexPathForSeparator];

  // If there is a separator, and this item is below the separator, shift the item down
  if (separatorIndexPath) {
      if ([separatorIndexPath compare:attributes.indexPath] != NSOrderedDescending) {
          f.origin.y += separatorHeight;
      }
  }

  return f;
}

The element shifting, revisited

If you implement the above, and run it, you’ll find that it mostly works, but sometimes there is a gap in the cells.

Uh oh. What gives?

Let’s think about how layoutAttributesForElementsInRect works. It asks for layout attributes of one screenful at a time. (Actually it seems to be two screenfuls on initial run, and one screenful after that, but let’s just think about one screen.) So at first pass, the parent FlowLayout object might give us attributes for items 1-8, next 9-16, then 17-24, and so on.

But: suppose our separator is above item 4 on first screen. So the first screen contains layout for objects 1-3, separator, 4-8. And then, 8 is out of the rect so its attributes are simply discarded. They do not “carry over” to the next screen. Then, at next run, for the next screen, the parent returns attributes for 9-16, but in our case, we might want 8-15. Since 8 is not included, we’ll see a gap in its place.

To compensate for that, there’s some extra math that I’m not pasting here but that you can see in the Github project, that figures out which extra cells to add to the rect, in addition to the ones returned by parent FlowLayout.

Conclusion

UICollectionView is a fairly involved class, but has a lot of flexibility. We can let the parent classes do most of the work, and slightly customize the results from them, instead of having to do a lot of work ourselves. You’ll see that my example project implementing the above solution doesn’t actually have all that much code.

Crysis 3

I finished Crysis 3 the other night. I’ve written about the first and second game in the trilogy before, so let’s wrap this one up.

Here’s a trailer that fairly accurately captures the feel of the third part.

Whereas Crysis and Crysis 2 were very different, Crysis 3 feels much more like a logical continuation of the second part, almost like a Crysis 2.5 rather than a completely new episode. There are some new gameplay elements, like the bow and alien weapons, and nanosuit customization, but overall, it is the same.

It is technically very well executed, a visually gorgeous game with epic landscapes and effects. Some critics say, though, that it is much too dark through a lot of the game. I also don’t like too dark ambiences, and there were a lot of those, though it kept alternating with brighter environments and I wouldn’t say it was too dark.

Still, if I were to have my preference in the series, it would be: Crysis 2, Crysis, Crysis 3. Somehow the third part felt the least fulfilling. Maybe I had outgrown the series or took too long to play the third part (took me about three months of playing every now and then). Hans Zimmer’s intro song was also more captivating in 2.

I like that the third part really does wrap up the trilogy in a meaningful way, and the trilogy overall is definitely one of the most solid instalments of modern FPS gaming.

Chaining Execution

Brent Simmons has a post about his quest to find a solution for blocking on object init while maintaining a synchronous API, and another one about how for most cross-object execution, it makes sense to stay on the main thread and only put background work on the background queue.

I haven’t had to solve the particular problem from his first post, but in a project that I’m working on, I deal with a significant amount of asynchronous execution. It mostly comes from two sources.

First, data. It comes from network, and thus it may or may not be there. Or, it may be there, but not cached/preprocessed in a correct way. So, if someObject deals with the above kind of data, and you have a call like…

1
2
[someObject prepareSomeData];
[self otherCodeToRunAfterPreparingData];

… there really are two paths here. If the data is there, doSomething may return immediately in the same runloop, and execution continues without a hitch. On the other hand, if the data is not there, execution may block for an indeterminate amount of time.

The other case is chaining animations. For a professional UI, it is not uncommon for multiple things to happen after some user input. For example, if you tap a button, it might trigger the following sequence of events:

  • One-shot button animation as feedback to user
  • Objects moving around in the UI (added, removed, shifted around)
  • Each of the added objects animating themselves
  • The object signaling some other object to dismiss a modal view that it was presented in

Running them all at the same time looks like a visual explosion and it is hard for the user to follow what’s happening. Correctly orchestrating such things is a strong sign of good UI polish.

Sometimes I’ve seen these animations chained by timing: the engineer calculates how long each animation takes, and delays the next one by that amount. Not only is this brittle and looks ugly in code, but it may introduce crash bugs, as the context may change during execution: the objects may go away without knowing it themselves, and happily try to run animation when it’s no longer valid to do so.

The solution to both of these things is to use block-based APIs. A strong indication to me that this is the right thing to do is that completion blocks keep popping up left and right in all of Apple’s new APIs. Some of the key ones like presentViewController:animated:completion: have been around for a while, but the trend continues with, say, NSURLSession that has completion handlers as blocks, unlike NSURLConnection that’s based on callbacks (and was, of course, designed long before blocks were a language feature to begin with).

Coming back to the above example, my code has API’s like this all over the place:

1
2
[someObject methodWithCompletionBlock:^{  code  }];
[someObject doSomething:parameter withWidget:widget completionBlock:^{  code  }];

The example from above would thus work better like this:

1
2
3
4
5
6
[self showProgressIndicator]; // maybe put up a spinner to show the user loading progress if it happens to take long
__weak TypeOfSelf *weakSelf = self;
[someObject prepareSomeDataWithCompletionBlock:^{
  [weakSelf hideProgressIndicator];
  weakSelf.something = somethingElse;
}];

A few things to note here.

First, note how we put up a progress indicator, and hide it in the completion block. In the “data available immediately” case, it’s shown and hidden in the same runloop, so it’s like it never happened in the UI. For “data available later” case, it’s immediately shown, and then hidden when appropriate.

Second, the weak self reference. It is absolutely essential to understand the strong and weak business when working with ARC, with code like this that you request to be executed, but have no control over its final scheduling or any idea when it actually gets run. Nor should you care, and if you set up the weak references correctly, you don’t. The block in this example may get run immediately. It may get run as part of a completion block of an animation or download. The target object may strongly retain it and run it after a hardcoded timer. It doesn’t matter. What matters is that your object may go away before the block gets run. When the block contains strong references to the object, it interferes with the normal expected execution flow and the object is held on to longer than you think, unless this really is the desired behavior (but most of the time with API-s like this, it isn’t). Strong references here may result in unexplained behavior, crashes, leaks, and who knows what else. If, on the other hand, you have a weak reference here, and your object happens to be released, then by the time execution gets to the block, weakSelf is treated as nil, and calling methods on nil is harmless. Note that you didn’t have to tear down the block or do anything special with it when your object is released.

Third, note the property usage. This didn’t just randomly appear in the example. If you were to manipulate any of the object’s data like variables in a block like this, the most straightforward thing to do is to make them properties. Were you to use an ivar directly in the block, it would create an implicit strong reference to self, and your memory management is again screwed. Accessing weakSelf properties, on the other hand, is fine.

An often-critiqued similar API is NSNotificationCenter addObserverForName:object:queue:usingBlock:. I think it’s a great API for running simple code triggered by notifications, and I have never myself had a single memory management problem with it, when I’ve stuck to the weak reference rules. It sounds an awful lot like people are blaming the tools for not being able to implement things correctly themselves. Sure, tools could be better to warn us about implicit strong references. Clang sometimes does this with warnings, and sometimes as static analyzer result. But all the tools are there today to do this correctly.

On the callee/target side, one thing to note is that the block may be nil, and if you then try to call it, it crashes. Just check for its validity. Other than that, nothing special, so this kind of nesting is pretty common for me these days:

1
2
3
4
5
6
7
8
9
10
- (void)someMethodThatTakesBlock:(void (^)(void))blockName {
  [self presentViewController:someVc animated:YES completionBlock:^{
      [UIView animateWithDuration:something animations:^{
           something
      } completion:^(BOOL finished) {
           wrap up the animation
          if (blockName) { blockName(); }
      }]   
  }];
}

(And yes. I did have to go to fuckingblocksyntax.com to see how to correctly write the method parameter.)

The moral in the end? It’s great to be working on iOS and Mac these days if you don’t have to go back in history and can use modern block-based APIs. Blocks and ARC together make it powerful, fun, and safe to deeply nest and chain execution while maintaining clean separation and tight API-s between objects.

Call of Duty: Black Ops

Finished the single player campaign a while ago. According to Steam, took me 8 hours. So it’s on the short side of shooter campains. Didn’t feel too short, though; just about the right length for this kind of game.

The trailer is, of course, impressive. But before I talk about the game itself, let’s talk about (not) getting it to work on Mac. (tl;dr: didn’t work for me.)

Technical problems on the Mac

I could not get it to work correctly. I first bought it from Mac App Store. It installed and ran fine, but at some point in the game, when you got killed, the game just froze with a black screen. (It is supposed to continue from the previous checkpoint in this case.) It kept doing that, so I thought, maybe something is wrong with the MAS version, and I try the Steam version. I asked MAS for a refund, which I got.

One thing about Apple’s customer service which I don’t think is acknowledged enough, is that they have a generous refund policy that doesn’t treat all customers as potential fraudsters. If you ask nicely for a refund and explain it well enough, you just get it, no questions asked. Compare this to Steam’s policy of “no refunds whatsoever under any circumstances.”

Anyway. Many games on Steam are such that you buy it and can install on both Mac and Windows. Not so with Black Ops, which has a separate Mac and Windows version. I bought the Mac one, and sure enough, it misbehaved the same way as the faulty MAS version. Aspyr tech support asked me to try a few things, none of which helped, so I just gave up.

So, I just bought the Windows version, which did not have any technical problems. So unfortunately, Mac still is not up to par for AAA gaming, and performance may vary considerably across titles. (Max Payne 3 had many technical problems. On the other hand, Half-Life and Portal series worked flawlessly for me.)

The game itself

The most important fact about the game is that the single player version was not memorable to me in any way at all. I like to play FPS/adventure games that innovate or contribute something. CoD has by now turned into a mindless franchise that just pumps out a new version every year like clockwork, but they’re shallow and don’t contribute anything to the genre.

It’s not a bad game. It’s well produced. Pieces of it are interesting. Like the whole premise of black ops with different episodes was something new, and the sequence where you switch between guiding special ops team from a SR71 Blackbird, and being said team yourself, was something new. But overall, meh. I’m not sure who their audience is, but I’m not that. And multiplayer is probably very good for people who play it, but I don’t.

What’s my benchmark? I’m now playing Far Cry 3 and Crysis 3. Both of them are way more interesting, especially FC3.

Max Payne 3 and Tropa De Elite

I recently finished Max Payne 3. (According to Steam, it took 17 hours.)

I really liked the first two games in the series, but knew that third one would be a major departure. It’s built by a different team and happens in a different place, years after the events of the first series.

Yet, when I now look back, I feel that it was more of a continuation of the series than I was expecting. Payne voice acting is by the same guy, the bad humor and painkillers are still there, a lot of the mechanics (bullet time) is true to the series’ legacy. Could have been much worse.

Game play wise, this is one of the most tactical shooters I’ve played recently. You really need to use the environment, cover and bullet time to your advantage. If you just run into a situation openly, you’ll get killed in no time, as you can only take a few hits. However, “last stand” is a cool mechanic to recover from this situation: when you get killed but still have painkillers left, you have an opportunity to kill the guy who almost-killed you, and then live on.

Here are some videos about the visuals and game mechanics.

Crossplatform dind’t work for me

One of the supposedly cool things was that the game eventually got released on both Windows and Mac on Steam. (Initially it was Windows-only.) You could play on any platform and share the savegames.

Well, for whatever reason, it just didn’t work. The Windows version (in Windows 7 with Bootcamp on Retina Macbook Pro) ran flawlessly. The Mac version had crappy frame rates, no matter how I tweaked it, and didn’t pick up the save games. I saw some patches published later for it, but it was too late for me then. Maybe it got fixed. But crossplatform gameplay on Steam seems to still be tricky.

Tropa de Elite

On the game’s Wikipedia page, the developers recommend Tropa de Elite, a famous recent Brazilian action movie, that depicts how the special police forces cleans up the favelas in big cities.

I was intrigued, as a lot of Max Payne 3’s action takes place in this exact environment, and the producers had cited this movie as a big inspiration. I wanted to see how close these things really are.

Well, they’re close and I think the producers did a great job. The ambience in the game is very similar to what you see in the movie, with all the Portuguese shouting, tight spaces, destructible environment, lighting, and other aspects. It really does feel like you’re right in that movie when you play. Only, unlike the movie, the game is much more ambiguous about who are the good or bad guys.

Recommendation

I do recommend you play the game if you were a fan of the first two games. It does take and expand the series in a new direction, but it’s a direction that I feel does justice to the legacy of the first two.