October 21, 2020 · Swift

Obscure APIs

Here are 5 APIs provided by Apple that you may not know about:

1. SearchKit

SearchKit is a C-level API that provides quick full-text search for your Mac apps. I've seen many questions about how to enable the full-text search extension in SQLite to use in CoreData or how to install and setup some third party library to enable search in their apps. None of this is necessary because Apple provided SearchKit back in MacOS 10.3. While it is a C API, it's a very specific API so I only find myself needing about 4 functions to enable search in my apps.

2. Language Detection

Since iOS 3 and MacOS 10.5 we have been able to detect the language used in text using CFStringTokenizerCopyBestStringLanguage. This is much more accurate than looking in your strings for Arabic or Japanese characters, for example. This comes in handy when you want to do content-aware text alignment, like I mention in my article about RTL Support. This is one I only recently discovered even though it has been in CoreFoundation for almost as long as I have been working on Apple platforms!

Update
My friend Paul has pointed out to me there's an even nicer way to do this with the Natural Language framework.

3. Asynchronous Fetching

I continue to hear complaints about CoreData in apps related to performance. I find that many of these people haven't heard about the improvements to CoreData made in the last 10 years to improve this. One of these additions is NSAsynchronousFetchRequest. For elaborate models and large piles of data, some of your fetches might be entirely too slow to do synchronously, but since iOS 8 and MacOS 10.10 you don't need to! With an asynchronous fetch, your app can remain responsive while you wait for the data, much like your app already waits for asynchronous network requests.

4. Progress

Progress was added in iOS 7 and MacOS 10.9. I only realized it existed and was useful when I started work on my app, Publicist. Progress is an object made for keeping track of the state of long running tasks. They can be linked to progress indicators in UIKit and AppKit and in SwiftUI they can just be directly handed to a ProgressView. They're already adopted by framework items like OperationQueue and URLSessionTask to show progress to the user in a simpler fashion. I've worked on apps before that wanted to show download progress and computed this manually, but now that's not necessary because you can just get the progress object from a url task and report it to the user (or monitor it yourself).

5. Custom Bindings

SwiftUI provides the new @Binding property wrapper to link data displayed in views to their source of truth. The system knows to update the displayed view when data changes and the view using the wrapper is able to change the data as well without owning it. I just found recently you can make your own Binding objects and you don't need to only send property-wrapper variables to views expecting a binding. For example, let's say you have an array of names in your data model, but want to display them in one single text field. You cannot just give your array to a text field, but you can provide a custom binding to do the translation work for you like this:

TextField("Names", text: Binding(get: {
  names.joined(separator: ", ")
}, set: { newValue in
  names = newValue.components(separatedBy: ", ")
})

This will join your array of names into one string to display in the text field and also translate whatever the user types back into an array of names in real time. I nearly wrote quite a bit of code to do this before I found this method!