Tewha.net Mostly about iOS.

Learn Swift

Jon Friskics suggets Swift is great, but you should still know Objective-C first. Dave Mark agrees.

Let me give you a different opinion:

No, newbie, you don’t need to learn Objective-C first. You’ll miss it from time to time and you might want to pick it up later, but it won’t help you much now. And it will color your thinking in a way that might hurt your understanding.

ARC, an admittedly imperfect analogy

Let me rewind a few years. Apple introduced Automatic Reference Counting, which let the compiler manage its own memory. To this day, people continue to suggest you learn manual release/retain (MRR) before using ARC. I used MRR for years, and it really didn’t help me learn ARC. What helped me was understanding the object graph model, which was actually hidden by MRR. I think knowing MRR can actually make it harder to learn ARC.

So should you learn MRR first? No. You should learn the concepts behind good memory management on iOS — something many programmers never learned under MRR — then apply them to ARC. MRR is mostly unrelated to this.

To any MRR people who just read this and are shaking their heads: No, you really don’t need to know it. You and I know that this chunk of code is slow because it’s doing extra retains and releases, but the ARC user might instead know it’s because they’re assigning a strong reference. And the funny thing is that’s probably a better way to think of it.

And none of this is to suggest that’s not to say people it isn’t helpful to learn MRR. MRR offfers a better perspective on some concepts, such as __autoreleasing, bridge casts, precise lifetime, consumed parameters. But I’m not at all convinced you need to learn MRR first, because I think the ARC concepts are generally more useful for a 5,000 foot view of what’s going on. When you’re hovering three feet over? Knowing MRR is great.

Swift

Just looking at it and playing for a few minutes, I think Swift is another great example of this. Swift is a teaching language that’s probably more useful for day-to-day programming tasks than the language it replaces. It’s also likely to be more performant than Objective-C, thanks to… well, that’s another article. :)

If you’re a new developer reading this, ignore Friskics’s article. Get the concepts down and then learn the language you’re going to use. Enjoy it. You don’t have to suffer like we did. You get to start from our shoulders, and that’s a good thing. Nothing prevents you from learning down as well.

In a few years I’ll miss Objective-C. But primarily because I felt there was always something to learn about it, and a better way to write my code. I’m not sure if I’ll still have that feeling with Swift, but that nostalgia doesn’t mean Objective-C is a better language.

To address his points:

  1. You can learn the frameworks in Swift just as easily as Objective-C. Apple’s designed Swift to work this way, and their documentation is already ready.
  2. Swift will be tried and true before you know it. This isn’t something Apple started working on the Tuesday before WWDC, and it’s not going final way off in 2016. Sure, Swift isn’t the main language yet, but it will be by the time you’re ready to ship something.
  3. The learning materials and code examples are already appearing, and they’re going to continue to appear.
  4. Just because you can mix languages if there’s a reason for it doesn’t mean you have to. Sure, we Objective-C programmers mix C code in if we have to. But it’s not the first thing we reach for.

Debugging app upload

I’ve had some recent troubles trying to upload a build in Xcode. These involved getting a really unhelpful error from Xcode: “No identities were available.” Unfortunately, I was stuck there for two days.

It turns out that you can get Xcode to log more information on the handshake with the portal. Quit Xcode, then run these two commands.

defaults write com.apple.dt.Xcode DVTCodesigningAllTheThingsLogLevel 3
defaults write com.apple.dt.Xcode DeveloperPortalLogLevel 3

Then, open Console. Quit anything spewing to it, clear the display, then try to upload your build again. When you’re done, select and copy the spew to Console and paste it into your favorite text editor. You’re looking for DeveloperPortal and DVTCodesigningAllTheThings rows.

The results aren’t exactly easy to interpret, but it does give you a better idea of what’s being reported to Xcode, as opposed to what Xcode displays. Xcode is probably simplifying the error message.

When you’ve solved your problem, you’ll probably want to turn it back off:

defaults delete com.apple.dt.Xcode DVTCodesigningAllTheThingsLogLevel
defaults delete com.apple.dt.Xcode DeveloperPortalLogLevel

In my case, I solved my major problem literally seconds before I learned about this logging trick: I had used a bundle ID of com.company.product, whereas I was now using com.company.${PRODUCT_NAME:rfc1034identifier}. That made the effective bundle ID of the new product com.company.Product, which was enough that Xcode couldn’t find a corresponding application for my bundle. I don’t know what that would have looked like in the log.

This logging trick did solve me with a subsequent problem, however, by letting me know it was based on permissions. As a result, I spent only seconds on that one, and my app is now waiting in Apple’s review queue.

I don’t know if this will help you or not, but if you’re getting only a generic error message it’s worth a try.

Built-in categories

NSIndexPath is easier to use than you might think.

If you read the documentation for the class, you’ll see this:

Creating Index Paths

+ indexPathWithIndex:

+ indexPathWithIndexes:length:

- initWithIndex:

- initWithIndexes:length:

- init

Yes, you can use these to construct an index path. But you probably don’t want to. UIKit defines a category on NSIndexPath specific to UITableView’s needs:

// This category provides convenience methods to make it easier to use an NSIndexPath to represent a section and row
@interface NSIndexPath (UITableView)
+ (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section;
@property(nonatomic,readonly) NSInteger section;
@property(nonatomic,readonly) NSInteger row;
@end

There’s a similar category defined by UICollectionView:

@interface NSIndexPath (UICollectionViewAdditions)
+ (NSIndexPath *)indexPathForItem:(NSInteger)item inSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
@property (nonatomic, readonly) NSInteger item NS_AVAILABLE_IOS(6_0);
@end

The absence of section in this category isn’t significant; the same property is already defined by NSIndexPath (UITableView).

UIKit defines other categories, such as drawing categories on NSString.

Why are these separated? Well, NSIndexPath is part of Foundation. UITableView is part of UIKit. String drawing is added to NSString which is part of Foundation, but Foundation, but uses UIFont which is part of UIKit. In short, there’s good technical reasons for this to be splatted out. But knowing that is not helpful to us developers.

So how do you find out about these methods? I don’t think there’s a good way to find categories like these in Apple’s class references. Some of them are mentioned in Apple’s less reference-like material. For instance, there’s ”Collections Programming Topics: Index Paths: Storing a Path Through Nested Arrays”:

In iOS, UITableView and its delegate and data source use index paths to manage much of their content and to handle user interaction. To assist with this, UIKit adds programming interfaces to NSIndexPath to incorporate the rows and sections of a table view more fully into index paths. For more information, see NSIndexPath UIKit Additions. For instance, index paths are used to designate user selections using the tableView:didSelectRowAtIndexPath: delegate method.

Google searches are probably your best bet, such as index path from row and section.

I hope we’ll see improvements on this in the future.

On Frameworks

A coworker sent me a link to this posting on the state of libraries on iOS. I sent back a quick reply, with the intent to write a blog post on the subject later.

I’ve since decided that this replay says almost everything I wanted to say, so I decided to just edit it a bit.

I’m pretty torn on this whole subject. Dynamic libraries can lead to inefficiencies in storage space if a developer isn’t careful, and I’ve no reason to believe iOS developers are careful. Include Google Toolbox for one function? Sure, why not? Apple’s always balanced the experience towards users, and even when it makes my life more difficult I like that.

The static library approach isn’t a good approach either. Sometimes I’ve had less than complete debugging info, and been missing information in crash logs. And its code stripping isn’t as good as it should be, either. The final straw for me was when HockeyApp’s crash reporter stopped producing useful stack crawls. I spent a few hours trying to fix this, even got a little help (HockeyApp is excellent, and their support is outstanding) but quickly realized I was spending too much time on a problem with a very pragmatic fix.

(What was the problem? I’m not sure. It seemed to be related to an Xcode update, but after a few hours I grew less interested in solving it and more interested in shipping what was a critical update to my app.)

Cocoapods tries to solve this, but I think it does so the wrong way. You still have the same problems, it’s just a little less trouble to keep it going. It’s probably better than nothing, but it wasn’t the approach I wanted to take.

What I’ve been doing recently is including the sources in groups within my project. This is harder for me, but better for the compiler/linker (it has a better sense of everything I’m trying to do), debugger (all the symbol information is built as part of the main project) and the end user (who gets a better stripped executable).

What we need is not static libraries or dynamic libraries or frameworks. We need something better, more tuned to iOS.

There’s a few options:

Until Apple has a good solution to this, I’m going to continue to avoid static libraries (except for very specific libraries, like HockeyApp) and put the sources in a group.

I really hope Apple comes up with a good solution soon, though. This is indeed painful. I think Landon’s radar is entirely positive; Apple isn’t too likely to just do the easy thing. They’ll think about, evaluate possibilities, then do something that we can hopefully live with. Hopefully something better than any of us anticipated.

Change back button title

When you’re using a navigation controller, the title of the back button on a particular view controller is pulled from the view it leads to.

Although this can be initially confusing, this actually makes a lot of sense. If two different view controllers (say, Circles and Squares) might push the same view controller (Details), shouldn’t the text in the top left of that view controller depend on which controller pushed it (Circles or Squares)?

Think of it this way:

thisViewController.visibleBackButtonTitle =
    previousViewController.navigationItem.backBarButtonItem.title
    ?: previousViewController.navigationItem.title
    ?: previousViewController.title;

This won’t compile; visibleBackButtonTitle doesn’t actually exist.

There are a few reasons to show custom text on the back button.

More generic

The most obvious reason is that your title relies on user input that may be too long, and you want something simpler and more generic.

This might be the case if the user taps an event. The title in the navigation controller should be the event’s title, but you might want to use something shorter like Event on the back button.

This case is simple: select the parent view controller and give it a custom Back Button value.

More specific

You might also have the opposite problem, where your context is not visible in the navigation title because it’s obvious from something else in the view controller. But you still want to leave that more specific title as a breadcrumb for the user.

An example of this might be an address without a label. The first line of the address doesn’t make sense as a navigation title, as it duplicates the view. But if you tap deeper than that, you might want to include something about the address, such as the house number of the position in the list.

This is a little more complicated. You’ll need to do this at runtime: Set the title of the backBarButtonItem for the navigation item of the view controller the button leads to. That will prevent the navigation item’s title from being used.

But there’s a wrinkle. Let’s assume you want to set the title dynamically. You might have something like this in your parent view controller, which is called by your viewWillAppear and whatever triggers updates of the view controller:

- (void)loadData {
    // lots of other stuff
    self.navigationItem.backBarButtonItem.title = @"dynamic title";
}

This probably isn’t going to work for you as is.

You’ll find lots of crazy solutions to this; manipulating the backBarButtonItem by hand and restoring it after for instance. (There are much, much crazier solutions.)

The key is understanding why it’s not working: backBarButtonItem is nil.

To make it not nil, you have two options:

  1. Select the navigation item in the storyboard editor and give Back Button a value. This value will cause the backBarButtonItem to be automatically created with the view controller is instantiated.
  2. Create the backBarButtonItem at runtime in your viewDidLoad or awakeFromNib (suggested by @calebd). I don’t recommend doing this in code; you’re already using a storyboard or nib, so it’s much simpler to just put a Back Button value into your view controller.

Once it’s created — whether in code or by storyboard — its title can be changed. You can change backBarButtonItem’s title at any time when the parent is displayed, as often as you like: it’ll only be shown when you push something else on top of it.

Summary

If the text is always the same:

  1. Select the parent view controller’s Navigation Item in the editor.
  2. Put the text into the Back Button value.

If the text is dynamic:

  1. Select the parent view controller’s Navigation Item in the editor.
  2. Put some text into the Back Button value.
  3. Set the title in the parent view controller, when its contents change: self.navigationItem.backBarButtonItem.title = dynamicText;

Empathy in pricing

I don’t know much about pricing products as a developer. While I’m a programmer, I don’t have apps of my own yet. So take this with a grain of salt, go ahead and flame me, etc. These are just my feelings.

But nevertheless, I wanted to share how I feel about pricing as a user of software.

I’m going to start with something bold, then work my way back to it: Never let me perceive your product’s pricing is unstable and currently at a high.

Read the rest of this entry