Init Question

What’s the best practice for this situation?

Let’s say you have an object where initWithSomething could fail due to bad inputs or other error.

Let’s also say that, if it fails, an error should probably be presented to the user.

If it helps to think about a concrete case, think of a Core Data stack object. (This post is not about Core Data. This is just an example.)

Init might look something like this:

- (instancetype)​initWithFolder:​(NSString *)​folder modelName:​(NSString *)​modelName databaseName:​(NSString *)​databaseName;

There are two reasons it could fail:

  1. Inputs are bad. (For instance: folder is nil, or modelName has a typo.)

  2. A method called during init fails. For example, -[NSPersistentStoreCoordinator addPersistenStoreWithType:​configuration:​URL:​options:​error:] could fail.

I can think of a few options, and I’m not sure I like any of them. So I’d love to know what you think.

Option 1: in-out error parameter

I don’t think I’ve ever seen a failable initializer with an in-out NSError ** parameter. (Do they exist? Maybe they do and I just haven’t noticed.)

The init method would look like this:

- (instancetype)​initWithFolder:​(NSString *)​folder modelName:​(NSString *)​modelName databaseName:​(NSString *)​databaseName error:​(NSError **)error;

That seems ugly and unconventional to me. But it would reflect reality pretty well.

Update 1:15 pm: This is the winner! Look at NSString.h to see some examples.

Option 2: error property

Don’t fail in the initializer. Instead, create a property for the error:

@property (nonatomic) NSError *initError;

The caller of initWith… would have to check initError right after to see if there was an error. Ugly and unconventional again.

Option 3: initialize lazily

The main reason for this object is to provide properties for other objects and hide how they’re created.

The example could have a property like this:

@property (nonatomic) NSManagedObjectContext *context;

All the initialization of the stack could be put off until context is first referenced.

But, then, there’s still the issue of what to do with errors. Something like this instead of a property?

- (NSManagedObjectContext *)context:(NSError **)error;

Ugh. Weird.

But maybe it’s less weird if the API is something like this:

@property (nonatomic) NSManagedObjectContext *context;
- (BOOL)setupManagedObjectContext:(NSError **)error;

The caller of initWith… will have to call setupManaged​Object​Context before referencing the context property.

This is also weird because setting up context should be completely in the hands of the Core Data stack object. It shouldn’t be something a caller has to remember to do.

Option 4: assertions and faith

Use NSParameterAssert and NSAssert to catch programmer errors in debug builds — then assume that, once programmer errors are fixed, nothing else that technically can fail will actually fail.

This would mean believing that, in this case, -[NSPersistentStoreCoordinator addPersistenStoreWithType:​configuration:​URL:​options:​error:] would never fail as long as the inputs were good.

Arguably you should just call abort() if such a method fails with good inputs, on the grounds that the device has probably caught fire.

But still, that requires a certain amount of optimism — but optimism means doubt, and our job as programmers is to remove doubt.

Option 5: don’t use a separate object for this

Give up on the idea of encapsulating all this in reusable code. Instead, have the app delegate (or similar high-level object) do the setup. Presumably that high-level object can show errors to the user and decide what to do if things go wrong.

This answer is a bummer, though. I like reusable objects and I don’t like copy-and-paste.

But maybe I’ve proven that this option is the only responsible choice.

What am I missing?

Ethics

Were software engineer a profession like doctor or lawyer, we’d have a strong and binding set of ethics.

I note that the ACM publishes a code of ethics. Here’s the first one:

  1. PUBLIC - Software engineers shall act consistently with the public interest.

Nowhere in the short list, or in the elaboration below, are the words “spy” or “monitor.” You could argue that you don’t need to call out those, because acting “consistently with the public interest” is enough.

But I think we’re at the point — between the NSA, draconian workplace monitoring systems, social network data collection, and malware — that calling out spying and monitoring specifically as unethical is warranted.

After all, you can argue that spying is necessary for national security, which is clearly in the public interest. And you can argue that workplace monitoring is either neutral (employers are within their rights to know what employees are doing with what resources) or a public good (more productivity is good for the economy).

But these are wrong.

Defining the lines gets interesting, though. Lots of apps collect crash logs and transmit them to the developers. Presumably there is some place where the user agreed to this collection. But is this monitoring? No. But defining things so that we can tell the difference, and so that the definition can handle scenarios not yet invented, could be tricky.

(Consent isn’t always enough. You may have to consent to workplace monitoring as a condition of employment. This isn’t, in many cases, a fair situation — not when you need a job to pay the bills.)

Another case: is it wrong to write code to spy on people who are actively planning to kill other people? Eeeesh. I would think not. But then how does the engineer assure that this is the only way that code would be used?

Assuming we could define things — a big assumption — then the value to society would be this: engineers would have the support of society when they refuse to do something that’s wrong. Right now they just lose their jobs.

But imagine if they could say, “No. I won’t. That violates the software engineering code of ethics,” and it would have the same weight as a doctor or lawyer refusing to act unethically.

And imagine if there were consequences when they didn’t refuse.

Reason Number 33,483 to Hate Programming

In one of the several apps I work on, I have a controller class that runs into a solution like this:

While the app is quitting, and things are being torn down, the controller class runs code it doesn’t need to run — because it watches for notifications of various types and does things. And code from elsewhere calls into the controller class for the same reason.

Well, that code shouldn’t run at app-quit time, since it’s extra work that doesn’t need to happen. And, worse, the object graph can be in a weird, partway-torn-down state, and any work done then could cause a crash.

The non-beautiful but acceptable and expedient solution was for the controller class to watch for the app-will-terminate notification and set an internal property (appIsTerminating) to YES when it gets it.

A few methods that I know for sure shouldn’t run at app-quit time (because they update the display) then return early when self.appIsTerminating.

This makes quitting faster, and some crashing bugs are avoided. And there are maybe 10 new lines of code.

(A better solution involves an audit of a bunch of code and a bunch of thinking and testing. Several days of work in this case. Possibly a week. Not worth it.)

But Here’s Where Things Get Ugly (or Uglier)

That controller class has a couple subclasses. Without those subclasses the parent class would have a bunch of nasty switch statements. Not good. Those subclasses are needed. (I like to avoid subclasses as much as possible, but there you go.)

But then I found that one of the subclasses also needs to know when the app is quitting — for the same reason of avoiding work at app-quit time. How should I do that?

It could register for the app-will-terminate notification also. With the same selector, and then have that method call super? I don’t think I’ve ever written a notification handler that called super. That means declaring it in the .h file for the superclass. Erg. (And never mind that the notification handler would be called twice, since superclass and subclass both register for that notification — which wouldn’t hurt anything, but smells bad.)

Or the subclass could not register for the notification, but know that the superclass does, and implement the notification handler (and still call super inside the notification handler). But then the subclass knows a weird secret about the superclass. (Sure. It already does know a few secrets. But I prefer to write my subclasses as if they don’t know anything about super’s implementation.)

Or I could have the superclass expose the appIsTerminating property in its header file, so that the subclass could see it. This also sucks, because a controller class has no business exposing its own copy of global application state.

In the end, though, that’s what I did. (Along with a comment that the property was there for subclasses.)

It reminds me that there are two competing values:

  1. Do everything the right way every time.

  2. Make responsible and professional decisions about time and expenses and benefits and drawbacks.

This is a super-small thing. The code I added is clear and obvious, and there’s very little of it.

But still it makes me itch. I did this work a few days ago and I went to bed last night thinking about it. (And out pops a blog post the next day.)

There are times when I think I’m way too fussy. There are times when I think I’m not nearly fussy enough. Often those are the same times. I don’t know which is correct.

Looping Through Objects in an Array

One way to loop through objects and stop when you’ve found the one you want is the following:

for (id oneObject in someArray) {
  if ([oneObject passesTest]) {
    return oneObject;
  }
}

The return could as well be a break statement. And the code in Swift would be something like this (typed without compiling; probably has errors, but you get the point):

for oneObject in someArray {
  if oneObject.passesTest() {
    return oneObject
  }
}

I’ve long been a fan of this. It’s easy to read and understand. It’s efficient because it stops as soon as the object is found.

It’s also pretty easy to make something re-usable: you could make a firstObjectPassingTest: category method that takes a block that performs the test. Easy.

In 10.6 Apple added - (void)enumerateObjects​UsingBlock:​(void (^)​(id obj, NSUInteger idx, BOOL *stop))block;

Mike Ash:

For simple enumeration, the block syntax doesn't really offer any advantage over fast enumeration and the for/in syntax. The syntax is a bit clumsier, and iteration is a bit slower. The code has to call your block for every object. This overhead is less than that of a message send, as in the NSEnumerator case, but is more than the simple C for loop of NSFastEnumeration.

There are cases — dictionaries in particular — where the block-based enumeration can be the best choice. But most of the time the for-in enumeration is the straightforward and less clever approach. (“Less clever” is a good thing.) It’s faster too.

And yet… I’ve been afraid to say this out loud, as it seems to me that the entire world is on a we-love-blocks-and-hate-loops kick. (Back this up? I can’t. I love blocks too, but I have nothing against loops, and I’ll take the simple, clear, readable loop over a blocks-based method when it makes sense, which is almost every time, though not every time.)

And then today there was this response from Chris Lattner (message #11). I can’t quote it because it’s on the confidential Apple forums. But I bet anybody who’s read this far also has access to the forums and knows who Chris Lattner is.

And now I feel better about for-in loops.

OmniFocus 2.1 for Mac Ships

Since starting at Omni late last September I’ve been working on OmniFocus 2.1 for Mac — and today it shipped. (It’s the first thing I’ve worked on at Omni to ship.)

The big changes are Yosemite-related: sharing menu, sharing and Today extensions, vibrant UI, new-style toolbar buttons, improved find-and-replace, and the tear-off view options popover. (Plus — my favorite — performance and stability fixes.)

OmniFocus, like every Omni app, is a team effort. It’s the work of engineers, designers, testers, project managers, writers, video-makers, and support humans — the whole company contributes, directly or indirectly, to every shipment.

While I’m proud of my work, I’m way more proud of the team’s work — because my work is just bits and pieces, and the team’s work is the entire app. And the app is good, and I feel good.

Three Xcode Tips

In case you don’t know these…

Really Clean

Instead of manually deleting the DerivedData folder, get Xcode to do it.

Hold down the option key, pull down the Product menu, and choose Clean Build Folder…

Normally that menu item is Clean…, but with the option key it’s really clean.

Keyboard shortcut: option-shift-cmd-K.

Callers

In that bar right above the source code, at top left, is a little icon made up of four rectangles. Click it to pull down a menu that includes a Callers submenu.

Put the cursor on any method name. Pull down the menu and see where it gets called.

(Note, however, that it won’t detect performWithSelector-style calls. So the Callers submenu could miss instances.)

The Find pasteboard

To search for some text, select it and hit cmd-E. The text will then appear in the find and search text fields.

No need to select the text, copy it, and then paste it into a text field.

Vaccines Again

Whenever the subject of vaccines come up, I remember my post from a few years ago about chicken pox. I wish the chicken pox vaccine had been available then. My eyes wouldn’t be so ruined.

What I didn’t tell in that original post — because I was so sick and barely aware of what was going on at the time, because my Mom told me about it after I wrote that post — was that I nearly didn’t survive. I was seriously dehydrated, since I couldn’t even sip water without throwing up, and I needed to go the hospital.

But there had been a blizzard. We lived at the bottom of a big, steep hill, and the car was parked at the top of the hill. My parents would have had to bundle me up and drag me on a sled up the hill to the car — and Mom tells me they weren’t sure I’d survive the trip.

Luckily I was finally able to drink a little water — well after going to the hospital was a good idea, but just before it was a desperate move in the cold and piled-up snow.

This is what these diseases are like sometimes. I’m reminded every single day when I take out my contact lenses and my vision becomes a solid blur.

Since I made it, since I survived, I can tell you about it. If I hadn’t, there’d just be silence where I would have been.

Update 1:15 pm: Mom reminds me it wasn’t water but cherry jello.

Xcode + UXKit

Don Mowry noticed that the latest beta of Xcode includes UXKit (Contents/​SharedFrameworks/​UXKit.framework).

I don’t know if it's a violation of an agreement to run class-dump on it.

The Repository of Crashes

It’s worth watching the swift-compiler-crashes repo on GitHub to see how many crashes are fixed in 1.2.

Swift 1.2 Beta

I didn’t expect to see this much improvement before WWDC. I’m very pleased.

Having accepted that Swift is Felix Unger to Objective-C’s Oscar Madison, I welcome changes that make Swift’s persnicketiness easier to satisfy.

My favorite change may be the improvements to if let. In the past, you’d write something like this:

if let a = foo() {
  if let b = bar() {
    doSomething(a, b)
  }
}

Now you can write:

if let a = foo(), b = bar() {
  doSomething(a, b)
}

(And more: you can include conditions with a where clause.)

So simple, so welcome.

I’m not sure what I think about the new annotations for Objective-C: nonnull, nullable, null_unspecified, and null_resettable.

On one hand it’s a leakage from Swift into Objective-C — as if Felix is wearing down Oscar until he gives in and picks his clothes off the floor and washes his hands 50 times a day. And it’s not like this has ever been a problem for me in Objective-C. (Objective-C’s nil-handling behavior was a delight when I switched from C, and I still like it.)

On the other hand, maybe I’m worn down a little bit too, and I don’t mind if the tools help ensure that my code matches my intentions. Most likely, though, I’ll use these only with Objective-C code that Swift needs to know about, because it will make things easier when writing Swift.

There are a bunch of other solid changes: read the release notes if you haven’t already. The day when I’m writing most code in Swift has just gotten closer.

With all the great things, we’re still not at Swift nirvana. I checked one of my favorite examples: impathic’s one-liner that takes 40 seconds to compile. It still takes about 40 seconds. But, well, that’s software development for ya.

PS Swift has a Set type now! I love sets. Use ’em all the time.

UXKit Again

Garrett Murray, one of the great iOS developers, tweets:

I do sort of dream of this world though where building UI for iOS/Mac/Watch all uses very similar code.

You could say that it already is very similar code. Everything under the hood is the same — Foundation is the the same, Core Data is the same, networking is the same, and so on.

The code that needs to be different is UI code. But, even there, you have so many things that are again the same (auto layout and storyboards) and things that are very similar, that use the same concepts with slightly different names (colors and fonts, gesture recognizers, view controllers, table views, text views, image views, popovers, and so on).

The big differences — and there are some — can’t be attributed to the frameworks: they’re differences of the platform.

An example: iOS uses navigation controllers for hierarchical data, while Macs use multiple panes. (I’m aware that iOS has split views, but, in general, iOS uses time where Macs use space. I’ve never seen a three-paned iOS app, and I hope I never do.)

Macs have menus and multiple resizable (closable, minimizable) windows. Macs have configurable toolbars; Macs have mice. Macs let you drag-and-drop between apps. Mac apps are scriptable.

By the time you’ve unified all this into one framework, you’ve either done a disservice to one or both platforms (by removing or changing things that people expect from the platform), or you haven’t really gained anything, as the differences between the platforms still need to be expressed in the framework, and learning how to write Mac apps would still be roughly the same-sized job it is right now.

Programmers like it when differences can be collapsed, when we can use one thing to make two things happen. But we also have to remember that different things really should be different — and not just different, but obviously different.

I have no illusions that I can talk any iOS developers into Mac development. I will say that it’s fun, though, for a bunch of reasons. Your apps run on the same machine as your development environment. You have the freedom to distribute outside the app store. You have a chance to write something that all your peers — many of whom are also programmers — will run all day long on their Macs. (And you have a decent chance of making better money. Mac users tend to be loyal and supportive and awesome.)

The thing to do isn’t to treat the Mac as a weird version of iOS, though. The Mac UI is great (though, like iOS, not without warts) and the platform is worthy of your understanding and respect. The thing to do isn’t to wish there were navigation controllers and similar on Macs — instead, it’s to figure out what’s the best Mac version of your UI. Different APIs are the last thing to be concerned with: you’ll learn those. The harder part — and the interesting and challenging part — is designing a great Mac app.

Update 4:40 pm: Garrett Murray follows up on his blog with some great points:

If I want to create a label, I’d love to create a UILabel (or, say, UXLabel) and know that by default it would perform in a logical way on all platforms. TableViews, animations, all of these core components would share a logical API you could use with little concern for how they behave and perform at the default level. Obviously, things like NSMenu would be on OS X only. That isn’t a deal-breaker for this. And sure, UXLabel might have some attributes available only on Watch. I think that’s all logical.

UXKit Skepticism

Some developers are excited to note that the new Photos app contains a private UXKit framework that, according to Jason Snell, “sits above the Mac’s familiar AppKit frameworks and strongly resembles UIKit on iOS.”

I doubt this will ever be available outside Apple as a framework that’s meant to replace AppKit.

Partly it’s a matter of resources. AppKit exists, and people make great apps with it. It’s hard to imagine Apple wanting to support another UI framework for developers outside Apple.

And it’s hard to imagine Apple adding this complication. Choice of language is one thing — but add the choice of UI framework and it looks like the company is flailing around.

It’s not like AppKit has stood still. With every release of OS X it’s more UIKit-like. It’s not a different country: it has auto layout, storyboards, view-based table views, gesture recognizers, and so on.

But AppKit also has things that don’t make sense on iOS: menus, resizable windows, resizable split views, AppleScript support, drag-and-drop between apps, mouse support, and so on. It has some time-saving (but optional) features such as Cocoa bindings that haven’t made it to iOS.

And UIKit has things that don’t make sense on Macs — navigation controllers and size classes, for instance. And where there are things that are the same on both platforms — toolbars, for instance — you’ll find that they’re not really the same.

AppKit and UIKit aren’t that different, and anybody working with one can switch to the other — with a learning curve, sure, but people who stick with one or the other are (hopefully) still always learning anyway.

But where they are different, the differences are critical.

With AppKit, Apple does what it does best: steady, incremental improvement. The AppKit of 10.10 is a very nice improvement over that of 10.9, as 10.9 was over 10.8, and so on. I expect that to continue.

Minimal UXKit

I could imagine a minimal UXKit that isn’t meant to replace AppKit but that can be used with both AppKit and UIKit. It might have UXColor, which would wrap UIColor and NSColor. Same with UXFont and UXImage. UXTableView could present a simplified superset of UITableView and NSTableView/NSOutlineView. Etc.

The point would be to make cross-platform development a little quicker — but it wouldn’t get you out of using UIKit and AppKit.

And, frankly, a bunch of this is super-easy stuff. You could make your own UXColor class by just defining it to UIColor or NSColor depending on target and adding category methods so that their interfaces match. (I’ve done this. I bet a bunch of people reading this have done it too.)

So I’m not sure there’s that much value in releasing a minimal UXKit — knowing that it would just be a source of feature requests and frustration, because it’s unlikely ever to do enough to make people happy who want to bring their iOS apps to the Mac.

What seems more likely is true convergence: imagine if, in the next OS releases, UIColor and NSColor, UIImage and NSImage, UIFont and NSFont, and so on were actually the same exact things.

My own experience

Would UXKit help OmniFocus or Vesper? No.

A Performance Enhancement for Variable-Height NSTableViews

Yesterday in one of the several Mac apps I work on I made a performance fix that could be useful to other people.

I have an NSTableView with variable-height rows. The height of the row is determined in large part by the height of the text in an NSTextField.

Unfortunately, text measurement is expensive, and measuring a ton of text as you resize a window causes terrible performance.

One common way to mitigate this is to use a cache so that you never measure the same text twice for a given width. And, in fact, there already was such a cache, so the performance wasn’t as bad as it would have been without it.

I did some testing in Instruments, and it told me that about 20% of the time spent during window resizing was calling the method that calculates row heights.

Then I noticed something about this particular case: quite often the text was just a single line. (Not always, but often. And it wouldn’t necessarily be true for all users. But true enough for enough users.)

So if the height was single-line-height at width n, the height would still be single-line-height at width n + x.

I wrote some code that takes that into account — and now Instruments reports that only 0.5% of the time during window resizing is spent in the calculate-row-height method. That’s a nice difference.

How It Works

There’s a property, calculated once, called heightForEmptyTitle. It stores the height of an empty string — @"".

There’s also a second cache (an NSCache), called singleLineWidthCache.

The method takes a title (the string to measure) and width.

The first thing to do is to ceil(width) — the title/width/height cache will be nearly worthless unless you round to integers.

Then it checks to see if heightForEmptyTitle has been calculated. If not, it does so.

Then it checks to see if title is nil or @"" — if so, then it just returns heightForEmptyTitle.

Then it looks for a cached height in singleLineWidthCache:

NSNumber *minWidthForSingleLine = [self.​singleLineWidthCache objectForKey:​title];
  if (minWidthForSingleLine) {
    if (width >= minWidthForSingleLine.​floatValue) {
      return self.​heightForEmptyTitle;
  }
}

If it finds it, and the passed-in width is greater than the cached width, then we know the height has to be the height of a single line, and we can just return that. (heightForEmptyTitle could also be called heightForSingleLine.)

If it doesn’t find it in the cache, or the width isn’t greater, then it moves on. It looks to see if that title/width combination is in the other cache (the cache that already existed in this method before I got to it). If so, it returns that cached height.

If it wasn’t cached there either, then it does string measurement. (By setting preferredMaxLayoutWidth on the NSTextField and then calling fittingSize.)

If it finds that the calculated height equals heightForEmptyTitle, then it may cache that information in the singleLineWidthCache.

if (titleHeight == self.​heightForEmptyTitle) {
  if (!minWidthForSingleLine || width < minWidthForSingleLine.​floatValue) {
    [self.​singleLineWidthCache setObject:​@(width) forKey:​title];
    return self.​heightForEmptyTitle;
  }
}

If it hadn’t found a previously cached value, or if the calculated value is less than the previously cached value, then it caches the new value.

Notes

The code assumes that the height of an empty title is the same as the height of a single line. This isn’t necessarily true (though it was true in my testing). The code is written so that when that assumption is incorrect, the only consequence is that you don’t get this caching. (You don’t get incorrect results.)

It also doesn’t do anything when multi-line text fields are more common. I have an idea for this, though. First look at all the cached height/width pairs for the title. If the passed-in width is between two cached widths that have the same height, then return that height. (In other words, if it has cached width/height 300/26 and 400/26, then a passed-in width of 350 should return a height of 26.) That’s something I still might try.

Also: I mentioned that this is for NSTableViews — but it works as well for NSOutlineView, and it ought to work on iOS as well (though it may be less needed there, since widths are less dynamic).

And it should go without saying that if something that affects text measurement changes — such as the font for the text field — then the caches should be tossed.

Random Swift Things

Last night I discussed Swift with some local developers. Some of it stuck in my head today. At random:

Question

It’s two years from now. Your company is hiring, and the best candidate has one drawback: all her experience is with Swift, and she’s barely acquainted with Objective-C. But she knows the frameworks well and has proven experience shipping quality software.

All of your existing code — and there’s a ton of it — is in Objective-C. Maybe there’s a little bit in Swift, maybe not, and maybe you’re open to doing more in Swift, and maybe not.

Do you hire this person?

Swift Is Hard

Objective-C looks hard because of the [ and ] syntax and all those words. It looks kind of mean, actually, like an angry grandpa with bushy eyebrows who makes you spell out “I am laughing out loud” instead of writing LOL.

But Objective-C is easy compared to Swift. Swift looks easier at first blush — every JavaScript developer sees it as familiar, and many think that this might be their way in to writing native apps.

More-familiar syntax will help more people get started, I think. But then you run into concepts that Objective-C doesn’t have to deal with (optionals, generics, and tuples, for instance) and concepts that Objective-C doesn’t have to deal with much (value versus reference semantics, functional design patterns, strict type safety). And you inevitably run into the issue of interoperation with Objective-C — which, obviously, isn’t a problem in Objective-C.

Angle-bracket-T Blindness

I’ll exaggerate a little — okay, a lot — to make a point. A popular form of blog post about Swift seems to be like this:

Here’s how you’d do things the crufty old-fashioned way:

for (id oneObject in someCollection) {
  [self doSomethingWithObject:oneObject];
  }

Well, you can tell by looking just how awful this is. Nasty loopses and untyped types. Let’s do it the modern way…

[snip]

[snip 200 lines of code]

func x<T> -> x<U> <TT> (in U -> <T>){$1 $2}.map(func y(T)<T><T> -> <U> infix $3 {

Clearly this is hyperbole and ridiculousness and line noise. I’m not being fair. But I think that anybody who reads a bunch of articles about Swift (as I do: I read everything I can find) recognizes what I’m talking about.

(There are many people who write wonderfully about Swift. Two of my favorites are NSHipster and David Owens II. But I still get angle-bracket-T blindness sometimes, even with them.)

Objective-C Hasn’t Finished Evolving

This is a prediction. It’s surely true that Apple has more existing Objective-C code than anyone else in the world. Improving Objective-C — especially if it means making their developers more productive and making their apps better — is in Apple’s best interest.

It’s possible we’ll even see some convergences — changes to Objective-C that make it easier for Objective-C and Swift to work together in the same code base.

I keep thinking it’s easier for Apple to upgrade Objective-C than to redo everything in Swift.

But Swift Is the Future

Swift’s adoption, and the enthusiasm around it, have surpassed my expectations — despite its very-much-still-early position. (If you have a developer account, read Apple’s Swift forum.)

Here’s the thing: if you go searching the web for solutions to some problem involving recent APIs, you’re extremely likely to run into Swift code. It’s happened to me plenty of times already — I’m translating from Swift to Objective-C as I read, which is not something I expected so soon.

Swift is happening.

P.S.

Yes, I’d hire the person with Swift experience but no Objective-C experience.

SCM Search

My co-worker and local hero Curt Clifton writes on Twitter:

Archiving 24,724 commit message emails to EagleFiler. Maybe Mail.app will actually perform reasonably after this. Fingers crossed.

Here’s the thing: this sucks.

At Omni, like many places, we get commit messages via email. (I have three filters and folders: one for mine, one for OmniFocus, and one for everything else.) It’s fine — email is a decent notification system.

The problem comes when I want to find something in a past commit message. Which happens all the time.

What I’d like is a commit-searching app that’s a desktop app (because I’m not going to remember yet another command line app’s arguments) that supports Subversion (which we use at Omni) and Mercurial and Git (both of which we use at Q Branch).

Were I to write this myself (I’m not going to) I’d probably use SQLite to store the messages and their metadata and SearchKit to make it searchable.

It’s possible that something like that wouldn’t work for Omni — with our hundreds of thousands of commit messages, a database on a server is probably better — but it would work for smaller teams.

Is this a money-making idea? I don’t know. But as a Mac app it would probably do better than whatever iOS app you were thinking of writing. (You’d get my money, at least.)

For the Glory

There are so many new buildings going up in Seattle — Boomtown — especially around South Lake Union where I work. And it seems that every in-progress building and every construction crane has a big blue 12 flag.

It makes me think of the religious art of the middle ages and Renaissance, except that our new civic religion is the Seahawks. As if all these buildings are going up as humble praise to our football team.

Which doesn’t make me sad. Go Hawks!

Gus on Microsoft and Apple

Gus Mueller, Microsoft, Apple, and Disappointment:

Apple is your favorite aunt or uncle, who isn’t talking about crazy future ideas, but is instead showing you how to hold a pencil correctly, or a tie your shoe. Something you can do today. Apple isn’t flailing about trying to grab onto whatever it can so, yelling out for attention. Apple is solid, reliable, dependable.

And I think that is why we’re seeing so many people reacting to Apple’s software quality lately. You expect Microsoft not to deliver. But we expect Apple to.

Wikipedia Draft Decision

Wikipedia’s Arbitration Committee [ArbCom] on Gamergate has produced a draft decision. Mark Bernstein writes:

By my informal count, every feminist active in the area is to be sanctioned. This takes care of social justice warriors with a vengeance — not only do the GamerGaters get to rewrite their own page (and Zoe Quinn’s, Brianna Wu’s, Anita Sarkeesian’s, etc.); feminists are to be purged en bloc from the encyclopedia. Liberals are the new Scientologists as far as Arbcom is concerned.

Frustration

When Mac and iOS developers get together, we complain about Apple bugs — which will always be true, whether or not the number and severity of bugs is actually high.

If we can’t grumble, we can’t be happy. So we grumble.

If you and I were sitting at a table, here’s the story I’d tell you:

WebView has a bug where scrolling is messed-up in some cases where you have a div that needs to stay anchored to one side of the window. (Think of a header that doesn’t move while the rest of the content moves.)

But the new replacement for WebView — WKWebView — doesn’t have this bug. Which is great. Let’s adopt the new thing! I’m all in. Love new things.

So I did, and it’s great. So happy. Until I noticed the console message:

Could not create a sandbox extension for '/'

I did some research, and I learned that WKWebView won’t show local content — that is, files that are loaded from the app’s bundle. Files from the app bundle ought to be a-okay, ought not be a sandbox violation, but apparently they are.

So while this works fine in my development build, research tells me it won’t work for the release build.

Do I need to write and embed a small web server in the app just to make this work? (Na ga da.) Instead, let’s just put the files on the web, because of course the web is safer than files distributed in the app bundle. (That right there was sarcasm.) It means the feature won’t work when off-line, but there are mitigating factors that make that mostly okay. Okay enough.

So: great. Problem solved!

Until, that is, I went to wire up the Find command. WebView has a searchFor:​direction:​caseSensitive:​wrap:. It’s not as great as the Find feature in Safari, but it’s okay for what I’m trying to do. (At least for now.)

WKWebView has nothing even similar. So now I don’t know what to do.

In an ideal world, WKWebView would work with files from the app bundle, and, as a replacement for WebView, it would have the same functionality as WebView (a searchFor or equivalent method). Anything else means running as fast as I can while I slip backwards.

Daniel’s Refactoring

Daniel Jalkut wrote about his adoption of NSURLSession — by writing a new cover class that has the same interface as his existing url-downloading code (which was a cover for CFNetwork).

This is the right way to do it. The callers — including the unit tests — don’t have to know anything about the implementation, since the interface is the same. That’s just good programming.

It’s also not how I would do it in this specific case.

My thinking:

It totally makes sense to have a cover class for CFNetwork, since it’s C-based but we want an Objective-C class. (I use FMDB for a similar reason — so I don’t have to use SQLite’s C interface.)

But I don’t like wrappers for things that are already written in Objective-C. (I don’t like subclasses either, except in cases such as NSOperation and UIViewController that are designed to be subclassed.)

Instead, I’d rather just use a thing directly, rather than write a class that wraps a built-in class.

The difference may be subtle, so I’ll use an example. Consider an RSS reader that needs to download a bunch of feeds.

Before NSURLSession, I’d create an NSOperation subclass that downloads a feed. That subclass would use NSURL loading classes to download a feed and eventually call back somewhere with the result.

Now with NSURLSession, I’d create an NSURLSession and NSURLSessionDataTask objects to do the downloading. No NSOperation subclasses.

In both cases I’d have an outside class — RSDownloadFeedsSession or something like that — that would have an unchanging interface. But, importantly, RSDownloadFeedsSession wouldn’t be a general wrapper for NSURLSession. It would just be a thing (inherited from NSObject) that uses NSURLSession.

The goal, in other words, is to stay close to the frameworks. Because:

  • Other people can understand my code more easily.

  • I can understand other people’s code more easily since I speak the standard Cocoa dialect.

  • I don’t have to worry about the curse of shared-code-that-wraps-things — that a change fixes App A but breaks App B. (Yes, unit tests may detect the breakage, but the point is to avoid the possibility of breakage.)

  • I don’t have to worry about the other curse of shared-code-that-wraps-things — that it will accrete features and configuration and special fiddly bits until it’s difficult to maintain and no easier to use than the thing it wraps. (I’ve been down this road.)

But here’s a point worth making: every good programmer has their own style, the way that works for them. Which means that Daniel’s approach is utterly right for Daniel, as mine is for me. Part of the deal with becoming a good programmer is learning about yourself — learning what your style actually is, and being comfortable with it evolving over time.

Update the next morning: Daniel responds. Daniel and I are doing things the same way more than not, which should not be a surprise.

Archive

Ads via The Deck