RxSwift: Typing/Idle Event Stream for NSTextView

To improve my note editing app The Archive’s responsiveness, I want to find out when the user is actively editing a note. Here’s how to create the idle switch in RxSwift/RxCocoa. A simple enum of .typing and .idle will do for a start. Of course, NSTextViewDelegate provides a textDidChange(_:) callback to hook into; it’s based on a notification, so you can also subscribe to the NSText.didChangeNotification directly if you don’t want to use a delegate. That’s the input signal I’m going to use.

Continue reading …

Broken Help Menu Breaks Rather Unpredictably

Last week, I wrote about the Help menu bug that seems to “freeze” apps inasmuch as it makes them not handle any keyboard input. The thing is, I cannot always reproduce this issue. I rebooted my system and just couldn’t break the behavior anymore. Which sounds an awful lot like running the system for a while and using it in a specific way might affect the Help menu’s behavior. But I don’t know which steps you need to take to reproduce this. It’s puzzling me. With Daniel Jalkut and a beta tester of my latest app having experienced the same issue, I know I’m not alone. Or crazy. Just clueless.

Continue reading …

Plain Controllers to Ease the Burden of View Controllers

I like to see that Soroush and I think among the same lines. For one, that makes me feel less like a loony. And since he writes a lot more in recent months, it means my sloppy blogging schedule does not affect spreading ancient wisdom. In February, Soroush blogged about writing “Just Controllers”: service objects, usually reference types, that you use to orchestrate processes and offer a simpler API. Requiring a delegate to be plugged-in is one way to design a simpler API: the delegate procotol defines all the output events from the service object, or controller. That’s all there is going to happen as far as outside code is concerned. But on its inside, the controller can do the fanciest of things to accomplish its goal. These implementation details are hidden from code that uses these service objects. It’s object-oriented programming 101 all over again – encapsulation, information hiding, stuff like that. But, and this is a big But, the go-to massive view controllers in iOS apps are a symptom of not encapsulating properly. Go and delineate a few more boundaries inside your app. As with raising children, boundaries help your code grow properly, too!

Put Test Files Next to Production Code for Better Discoverability?

The Kickstarter engineering team posted an interesting proposal: put your XCTestCase files into the same directory and group as your production code. Do keep the separate target ownership, of course.

One clear benefit is directory tree or file management, and discoverability of tests for people browsing the code: In most cases, you have FooService in FooProject/FooApp/FooService.swift, and FooServiceTests in FooProject/FooAppTests/FooServiceTests.swift. With nested folders, you need to navigate around even more. I got used to this Xcode default. But I also got annoyed by this split at the root level when I browsed code on GitHub. Multiple tabs in a modern browser to the rescue, this was never that problematic, given the test directory is structured in a similar way. If not, good look finding the file you’re looking for. (I hate that the RxSwift project, which I often had to browse to look up an implementation detail, has files that contain only a path reference to the real file, similar to ../../Core/SomethingSomething.swift, making tests pretty hard to find).

I will try this approach with a library module that I develop as a sub-project of The Archive and report back.

High Sierra: Help Main Menu is Broken and Freezes Apps

If you run macOS 10.13 High Sierra, try not to use the Help menu. It will appear to freeze the app for which you invoke the Help menu: it will not accept keyboard input anymore, emitting the NSBeep “invalid action” sound in most circumstances. The reason seems to be that the nifty Search bar inside the Help menu will acquire focus so you can search for a menu item or help book entry. This is taking away focus from the app window. You notice this when the blue focus ring around an active text field in the window goes away; instead, the Help menu’s Search bar obtains focus and the accompanying blue focus ring. All this is supposed to happen. This process just isn’t reverted for some reason since at least macOS 10.13.3, maybe earlier. When you click back into the app outside of the Help menu, the key window status will not be assigned back to the window you click on. That means keyboard input will not work at all. (As a non-native English speaker, I asked if “key window” was supposed to mean “window that responds to key events” a while back. While people agreed this wasn’t the intention, I still cannot help to think that way. The app has no key window, so key events are not handled, resulting in NSBeep.)

Continue reading …