Tewha.net Mostly about iOS.

How to fix UITableView rows changing size

Do you have an app where the row heights in a table view shift, especially when navigating away from a view controller?

This seems to be an iOS bug and is caused by using autolayout within a table cell without a tableView:estimatedHeightForRowAtIndexPath: method.

If you do not implement this method, the UITableView will treat that as an estimated row height of 0. AutoLayout will panic and try to compensate for this, and you’ll still see an incorrect size. (I believe this to be the minimum size that it thinks would satisfy your content without any spacing and taking wrapping into account, but I’m not sure of this.) You see this bug in some of Apple’s apps, including Settings.

To fix it, you need to implement tableView:estimatedHeightForRowAtIndexPath: and return a rough estimate of the size of the row. iOS includes a constant for this, if you have no good estimate: UITableViewAutomaticDimension.

This may introduce a few other (minor) problems, as providing estimates can lead to views being poorly sized as you scroll. Apple discusses this in their documentation. If you are impacted by something like that, a tableView:estimatedHeightForRowAtIndexPath: that returns values closer to actual might help. That said, while I had problems from rough estimation on the simulator I’ve never noticed it on a real device. Seems like the logic is a bit different between them.


So what should you do? It really is this simple:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;

And you’re done!

Defending Facebook

You know what I really hate? Defending Facebook.

CBC has a story right now on how Facebook Messanger captures more data than you think. And thanks to how inaccurate that story is, now I have to defend Facebook. Way to make my day, CBC.


Do you care if Facebook knows which way you hold your phone or which UI elements you use within the Messenger app to work?

How you use the UI is useful to them in aggregate, as it helps them improve the UI if they find people taking inefficient paths, backing out of screens immediately (they probably tapped the wrong thing), etc. They can certainly tell all these things if you use the website; that’s just part of how the web works.

I’m not a fan of analytics and I wouldn’t do it in my own apps. First, if you don’t burst those transmissions with other data, it’ll drain the battery a lot faster. Even if you do it’ll drain it a bit faster. But also, unless you explicitly opt into the analytics – and not as part of a general Terms of Service, like you probably did with Facebook – it’s skeevy.

But remember this app is replacing a website. All of this data would be sent to a website from a web browser anyway. For a company replacing a web browser, building in analytics like this probably seems an obvious choice. Certainly, if you think going back to using the website will save you from Facebook knowing how if you opened this menu here or how you to delete a message you’re wrong.

Going back to my question: Does it matter if Facebook knows which way you hold the phone when you type, to use one of the examples from the CBC article? No, of course not.

As a sidebar – I don’t have sidebars – I don’t even run basic analytics on this site. I do outsource the creative commons badge on the bottom of this page, and there is a script link to App.net. It’s technically possible that they do something. I write because I enjoy writing. I don’t really care who reads it. I bet CBC runs a lot more analytics. Probably as many as Facebook’s Messenger.

Memory representation

Zdziarski also makes a point about how credit cards are stored in memory.

Memory is memory; the iPhone never writes swap pages to disk. Everything you do on your computer is stored in memory. It’s all transient, and it all goes away.

Worrying about credit cards being stored in memory is alarmist garbage. If you’re worried about someone connecting a debugger to an app, stop.

Private API

Zdziarski says that Facebook Messenger uses private API to get the name of your Wi-Fi SSD.

No, it doesn’t. The Wi-Fi SSID is available as part of the public API since iOS 4. I use this on some of my networking screens to let the user know which network they’re connected to, so my users can tell if two devices are on the same WiFi network.

Holding everything else constant, “No iPhones running MyAppName found on PARKSIDE,” is simply a better message than “No iPhones running MyAppName found on your Wi-Fi.”

I don’t have permission to share the code I use. I didn’t even ask, because I found similiar code on stackoverflow. The key point here is that CNCopyCurrentNetworkInfo (a public API) returns a NSDictionary of information. If you don’t know what that means, a rough translation is “There’s a call in the public API that tells you everything about the network that Apple thinks its okay for you to know.” The SSID is in there. It’s part of Apple’s public API.

Understand, I’m not vouching for Facebook

I have no idea how the Facebook Messenger app works. For all I know, it’s a giant mess of holes.

But I think if there were real holes here, we’d probably have better examples than looking at the name of your SSID or which button you tapped.

We’re all focusing on the wrong thing

While we’re raging about Facebook collecting too much data here because they know which way your phone is facing, how they store data in memory, or that they know the name of your SSID we’re missing the obvious.

Has Facebook built a system where your messages are really secure, not just from hackers but from them? No.

You should be worried about sending the contents of your message through Facebook, whether you’re using the website or the app. Are they going to look at it? Probably not. Could they if they wanted to? Absolutely. Will they if it’s part of a broad data collection warrant? Yes, of course.

If you care about privacy, use truly a secure system.

By the way, did you jailbreak your phone?

Just so you know, that disables a lot of Apple’s security precautions. It won’t make a difference here, but if you’re worried about Facebook Messenger’s security with a jailbroken phone… I’m laughing.

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.


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;

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);

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.