Development Quickies

From macwrench
Jump to navigation Jump to search


In diesem Artikel findet sich eine Sammlung diverser Tips und Tricks zum Thema macOS-/iOS-Softwareentwicklung mit Xcode, die im Alltag immer wieder nützlich sein können. Falls bereits aus einem dieser Quickies ein eigener Artikel entstand, ist dieser jeweils am Ende der Beschreibung verlinkt.

app extensions

Things learned while writing WidgetKit app extensions

Multiple instances (sizes) of the same widget ...
... apparently run within the same runtime environment so avoid writing data from the configuration intent to some kind of singleton or static class since it will be overwritten by a second instance with a different configuration. But on the other hand don't rely on this data on being shared across widget instances. This seems to be an undocumented bejavior and may not always apply, and it might change in the future.
Self-Updating widgets/High frequency updates
Some people suggest you should reload the timeline from within getTimeline() by calling WidgetCenter.shared.reloadAllTimelines() in order to achieve a higher update frequency of your extension. But doing this will drive up the cpu load, inevitably drain your battery and shorten the devices' life span in the process. So better avoid such dirty hacks and stick to the original plan for updating your widgets as laid out in Apple's documentation. Get used to the fact that high frequency updates of WidgetKit app extensions are simply not possible any more. Rather file a complaint with Apple, maybe they listen sooner or later and provide a proper mechanism for this specific use case.
When your extensions write shared data to a shared resource
Make use of semaphores when writing shared data to a shared resource such as a keychain or a user defaults store. You may run into race conditions when multiple instances of the same app extension can process or show different data, especially when they are configurable (i.e. have a configuration intent). They may have to write something in there simultaneously as they might receive an update trigger at the very same time and write operations on a shared keychain aren't always blazingly fast.

check if we're running within an extension

at compile-time

Objective-C

#ifdef TARGET_IS_EXTENSION
     // this piece of code will only be compiled when building for app extension targets
#endif
at runtime

Objective-C

if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) {
    // this is an app extension
}

Swift

if Bundle.main.bundlePath.hasSuffix(".appex") {
    // this is an app extension
}
or
if Bundle.main.bundleURL.pathExtension == "appex" {
    // this is an app extension
}