Message passing between iOS apps and extensions.

Last update: May 9, 2022

MMWormhole

MMWormhole creates a bridge between an iOS or OS X extension and its containing application. The wormhole is meant to be used to pass data or commands back and forth between the two locations. Messages are archived to files which are written to the application's shared App Group. The effect closely resembles interprocess communication between the app and the extension, though true interprocess communication does not exist between extensions and containing apps.

The wormhole also supports CFNotificationCenter Darwin Notifications in an effort to support realtime change notifications. When a message is passed to the wormhole, interested parties can listen and be notified of these changes on either side of the wormhole. The effect is nearly instant updates on either side when a message is sent through the wormhole.

Example App

Example

[self.wormhole passMessageObject:@{@"buttonNumber" : @(1)} identifier:@"button"];

[self.wormhole listenForMessageWithIdentifier:@"button" 
  listener:^(id messageObject) {
    self.numberLabel.text = [messageObject[@"buttonNumber"] stringValue];
}];

Getting Started

Note

The MMWormhole Example app will only work with your shared App Group identifiers and Entitlements and is meant purely for reference


Installing MMWormhole


You can install Wormhole in your project by using CocoaPods:

pod 'MMWormhole', '~> 2.0.0'

Carthage compatible
MMWormhole also supports Carthage.

Overview

MMWormhole is designed to make it easy to share very basic information and commands between an extension and it's containing application. The wormhole should remain stable whether the containing app is running or not, but notifications will only be triggered in the containing app if the app is awake in the background. This makes MMWormhole ideal for cases where the containing app is already running via some form of background modes.

A good way to think of the wormhole is a collection of shared mailboxes. An identifier is essentially a unique mailbox you can send messages to. You know where a message will be delivered to because of the identifier you associate with it, but not necessarily when the message will be picked up by the recipient. If the app or extension are in the background, they may not receive the message immediately. By convention, sending messages should be done from one side to another, not necessarily from yourself to yourself. It's also a good practice to check the contents of your mailbox when your app or extension wakes up, in case any messages have been left there while you were away.

MMWormhole uses NSKeyedArchiver as a serialization medium, so any object that is NSCoding compliant can work as a message. For many apps, sharing simple strings, numbers, or JSON objects is sufficient to drive the UI of a Widget or Apple Watch app. Messages can be sent and persisted easily as archive files and read later when the app or extension is woken up later.

Using MMWormhole is extremely straightforward. The only real catch is that your app and it's extensions must support shared app groups. The group will be used for writing the archive files that represent each message. While larger files and structures, including a whole Core Data database, can be shared using App Groups, MMWormhole is designed to use it's own directory simply to pass messages. Because of that, a best practice is to initialize MMWormhole with a directory name that it will use within your app's shared App Group.

Initialization

Initialize MMWormhole with your App Group identifier and an optional directory name

Objective-C:

self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"group.com.mutualmobile.wormhole"
                                                     optionalDirectory:@"wormhole"];

Swift:

let wormhole = MMWormhole(applicationGroupIdentifier: "group.com.mutualmobile.wormhole", optionalDirectory: "wormhole")

Passing a Message

Pass a message with an identifier for the message and a NSCoding compliant object as the message itself

Objective-C:

[self.wormhole passMessageObject:@{@"titleString" : title} 
                      identifier:@"messageIdentifier"];

Swift:

wormhole.passMessageObject("titleString", identifier: "messageIdentifier")

Reading a Message

You have two options for reading a message. You can obtain the message for an identifier at any time by asking the wormhole for the message.

Objective-C:

id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];

You can also listen for changes to that message and be notified when that message is updated.

Objective-C:

[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier" 
 listener:^(id messageObject) {
    // Do Something
}];

Swift:

wormhole.listenForMessageWithIdentifier("messageIdentifier", listener: { (messageObject) -> Void in
    if let message: AnyObject = messageObject {
        // Do something
    }
})

Designing Your Communication Scheme

You can think of message passing between apps and extensions sort of like a web service. The web service has endpoints that you can read and write. The message identifiers for your MMWormhole messages can be thought of in much the same way. A great practice is to design very clear message identifiers so that you immediately know when reading your code who sent the message and why, and what the possible contents of the message might be. Just like you would design a web service with clear semantics, you should do the same with your wormhole messaging scheme.

Communication with WatchConnectivity

The design of your communication scheme is even more important when you need to support watchOS 2. MMWormhole supports the WatchConnectivity framework provided by Apple as an easy way to get up and running quickly with a basic implementation of WatchConnectivity. This support is not intended to replace WatchConnectivity entirely, and it's important to carefully consider your watch app's communication system to see where MMWormhole will fit best.

Here are two things you need to know if you want to use WatchConnectivity support in your app:

  • MMWormholeSession is a singleton subclass of MMWormhole that supports listening for WatchConnectivity messages. It should be used as the listener for all MMWormhole messages you expect to receive from the WatchConnectivity framework. Be sure to activate the session once your listeners are set so that you can begin receiving message notifications.

  • Use the MMWormholeSessionTransiting types described below when creating your wormholes, but be careful not to send too many messages at once. You can easily overload the pipeline by sending too many messages at once.

Message Transiting Options

The mechanism by which data flows through MMWormhole is defined by the MMWormholeTransiting protocol. The default implementation of the protocol is called MMWormholeFileTransiting, which reads and writes messages as archived data files in the app groups shared container. Users of MMWormhole can implement their own version of this protocol to change the message passing behavior.

There are three new implementations of the MMWormholeTransiting protocol that support the WCSession application context, message, and file transfer systems. You may only use one form of transiting with a wormhole at a time, so you need to consider which type of messaging system best fits a given part of your application.

Most apps will find the application context system to be a good balance between real time messaging and simple persistence, so we recommend MMWormholeSessionContextTransiting as the best place to start. Check out the documentation and header comments for descriptions about the other messaging types.

You can get started quickly with a wormhole using one of the built in transiting types by calling the optional initializer to set up an instance with the right transiting type for your use case.

Objective-C:

self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"group.com.mutualmobile.wormhole"
                                                     optionalDirectory:@"wormhole"
                                                     	transitingType:MMWormholeTransitingTypeSessionContext];

Swift:

let wormhole = MMWormhole(applicationGroupIdentifier: "group.com.mutualmobile.wormhole", 
								   optionalDirectory: "wormhole",
								      transitingType: .SessionContext)

Requirements

MMWormhole requires iOS 7.0 or higher or OS X 10.10 or higher. MMWormholeSession requires iOS 9.0 or higher.

Troubleshooting

If messages are not received on the other end, check Project->Capabilities->App Groups.
Three checkmarks should be displayed in the steps section.

Correct App Group Capabilities

Incorrect App Group Capabilities

Credits

MMWormhole was created by Conrad Stoll at Mutual Mobile.

Credit also to Wade Spires, Tom Harrington, and Rene Cacheaux for work and inspiration surrounding notifications between the containing app and it's extensions.

License

MMWormhole is available under the MIT license. See the LICENSE file for more info.

GitHub

https://github.com/mutualmobile/MMWormhole
Comments
  • 1. MMWormhole does not work when passcode is enabled and iPhone is locked

    I'm using MMWormhole in my Watch app. My Watch does not have passcode, iPhone 5s does have it set. Messages are being passed around ok while the phone is unlocked and for some period after the screen goes off.

    After few minutes, it just stops and no data come in. I debugged it in and seems that iOS (8.3) cuts off access to the archive files. This data in

    NSData *data = [NSData dataWithContentsOfFile:[self filePathForIdentifier:identifier]];
    

    in messageObjectFromFileWithIdentifier: is always nil. As soon as I unlock the phone, then it returns the data properly.

    Anyone knows a solution to this? I don't know if this is "working by design" or is some tightened security in 8.3, but it pretty much renders MMWormhole not usable for watch apps.

    Reviewed by radianttap at 2015-05-09 07:50
  • 2. Queueing messages, instead of saving only the most recent one

    Any plans to support storing the sequence of messages in the order they were posted, so if an extension posts many of them while the app is away then they all can be received on the next launch?

    If you have no plans to do this, then do you have any suggestions for me while implementing that myself in a way that you'd accept in a pull request? Should I add separate methods queueMessageObject:identifier: queuedMessageWithIdentifier:? Or, what I'm preferring, should there be boolean property that can be turned on for a MWWormhole which changes the semantics of the existing methods?

    Regarding those semantics, presumably messageWithIdentifier: would remove the oldest message passed to the wormhole and return it, or return nil if none, so that it can be called repeatedly to get all of them.

    The listener block would be called upon notification as before, passing in the message, which gets automatically removed from the queue. But if the other side hasn't pulled out all the preceding messages yet, then this message will be received out of order. I'm thinking that the listener should have the option of making explicit calls to messageWithIdentifier: to catch any that its missed, where the passed-in object would presumably be at the end of those results. (I'm considering the case where the app polls for stored messages on launch then sets up the listener afterwards, and how to ensure any messages sent during that gap are received in order). Its seems that the notification code that calls the listener needs to initially leave its message in the queue, then be wary of it possibly getting removed "behind its back" once the listener returns.

    At the moment, I'm not sure what would be expected if once side turns on queueing and the other doesn't, but I'm sure some reasonable behavior can be chosen.

    Lastly, I was originally wanting to add support for this just by subclassing MWWormhole, but I believe there's no way to make that work well. If you think I'm wrong about that please let me know.

    Reviewed by jpmhouston at 2015-03-10 23:39
  • 3. Exposes darwin notification sending in public header

    We wanted to send a notification without data. This PR simply exposes the darwin method in the public header. Also, because the instance method made no references to the state I moved it to a class method. To minimize the changes, I kept the internal instance method. Let me know if this is helpful.

    Reviewed by felixLam at 2015-02-26 19:10
  • 4. Add support for NSKeyedArchiver

    We plan to add support for NSKeyedArchiver by checking the contents of the passed message. If the contents can be serialized as JSON they will be. If not, they will fall back to NSKeyedArchiver/NSCoding support.

    Reviewed by cnstoll at 2014-12-08 19:32
  • 5. Adding Message Persistence Subclass Support

    Hey Everyone,

    I'd love for you to take a look at this pull request to update MMWormhole's support for subclasses to modify message passing and persistence behavior. The need for this type of support has been apparent for a little while. There were two clear use cases for this:

    • Changing file writing security permissions
    • Adding support for message queueing

    Two more obvious use cases also became clear within the last week or two:

    • Apple apparently fixed File Coordination in iOS 8.2, and released a tech note indicating that it should be used when reading and writing files between apps and extensions. Adding subclass support allows that to be added as a modular addition to MMWormhole. https://developer.apple.com/library/ios/technotes/tn2408/_index.html Thanks to @atomicbird for highlighting this.
    • Its very possible that Apple will release some form of first party message passing API at WWDC. Adding this sort of modularity to MMWormhole paves the way to support their API (if they add one) and allow people an easy way to keep their MMWormhole logic in place while supporting the latest tech from Apple.

    The implementation below breaks out the various methods involved in message passing into a protocol called MMWormholeTransiting, named for the way in which a space ship would "transit" space and time. It has one base implementation and one subclassed implementation. The base implementation is the default when you instantiate a wormhole that functions the same way it does today. The second is a new implementation that uses NSFileCoordinator to synchronize access to files.

    Please take a look and let me know what you think. While this really doesn't add any significant complexity to the public API for MMWormhole, it's still a major architectural change and I want to get feedback on it before we move forward.

    Thanks,

    • Conrad
    Reviewed by cnstoll at 2015-05-27 20:25
  • 6. listenForMessageWithIdentifier always returns 'nil' in callback messageObject

    Trying to use this to communicate from phone to watchKit app and having trouble receiving the messageObject in 'listenForMessageWithIdentifier' callback. The listener gets fired (confirmed with breakpoints) but the 'messageObject' is always nil.

    Phone Code:

    self.wormhole = MMWormhole(applicationGroupIdentifier: "my.group.identifier", optionalDirectory: "wormholeDirectory")
    self.wormhole?.passMessageObject(["sayHello": true], identifier: "wormholeMessageIdentifier")
    

    WatchKit Extension Code:

    self.wormhole = MMWormhole(applicationGroupIdentifier: "my.group.identifier", optionalDirectory: "wormholeDirectory")
    self.wormhole?.listenForMessageWithIdentifier("wormholeMessageIdentifier", listener: { (messageObject) -> Void in
            if let object = messageObject as? [String: AnyObject]
            {
                if object["sayHello"] as Bool
                {
                    ...code...
                }
            }
        })
    
    Reviewed by Appmazo at 2015-04-09 03:58
  • 7. Not getting message in Swift

    I'm facing some issues. Kindly answer me to fix the issue. On iPhone app side I'm using this

    let wormhole : MMWormhole = MMWormhole(applicationGroupIdentifier: "group.com.xyz", optionalDirectory: "ProjectDataDict") wormhole.passMessageObject("message recieved or not?", identifier: "ProjectData")

    Just this code on iPhone side no. And on swift side I am doing this

    wormhole = MMWormhole(applicationGroupIdentifier: "group.com.xyz", optionalDirectory: "ProjectDataDict") let messageObj = wormhole.messageWithIdentifier("ProjectData")

    But it is not giving me any message. Kindly tell me the issue. . .

    Reviewed by TaimoorAli-Sematree at 2015-11-24 10:27
  • 8. Xcode 7 build warnings

    Getting the following build warning with Xcode 7 -

    /MMWormhole/Source/MMWormholeFileTransiting.m:36:17: Method override for the designated initializer of the superclass '-init' not found

    Reviewed by rmsutton at 2015-09-11 02:20
  • 9. MMWormholeSession and WatchConnectivity Support

    This PR includes a new subclass of MMWormhole called MMWormholeSession that is intended to help make things easier for existing users of MMWormhole to migrate their Apple Watch apps to watchOS 2 and the WatchConnectivity framework.

    http://conradstoll.com/blog/2015/6/10/mmwormhole-and-watchconnectivity-on-watchos-2

    Reviewed by cnstoll at 2015-06-10 15:36
  • 10. Multiple notifications

    We encountered this issue in our WatchKit app:

    ISSUE: Calling listenForMessageWithIdentifier n times for an identifier will register n callbacks at the DarwinNotifyCenter. When passing a message, the wormhole broadcasts it n times.

    SOLUTION: A possible solution would be to change registerForNotificationsWithIdentifier by adding:

    [self unregisterForNotificationsWithIdentifier:identifier];

    Like this:

    • (void)registerForNotificationsWithIdentifier:(NSString *)identifier {

      // Only registers once!!! [self unregisterForNotificationsWithIdentifier:identifier];

      CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter(); CFStringRef str = (__bridge CFStringRef)identifier; CFNotificationCenterAddObserver(center, (__bridge const void *)(self), wormholeNotificationCallback, str, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); }

    Reviewed by halkmund at 2015-06-01 11:41
  • 11. a crash

    hi,i find in sometimes the listenerBlock will call a lot of times and then crash,is it i call pass message with same identifier too quickly so that the first is not save succeed?

    Reviewed by yangzhihao at 2015-03-30 07:00
  • 12. I am getting this error when i am running my project Although App Group Capabilities are configured

    *** Assertion failure in -[MMWormholeFileTransiting checkAppGroupCapabilities], /Users/SunilSingh/Desktop/Sunil.Singh_BHAVNAWS410sMBP_8131_Centrify_MobileClient/depot2/Cloud-Mobile/Apps/iOS-pas/Pods/MMWormhole/Source/MMWormholeFileTransiting.m:62 2021-01-02 21:50:28.480348+0530 MobileManagerWatchExtension[97737:329645] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'App Group Capabilities may not be correctly configured for your project, or your appGroupIdentifier may not match your project settings. Check Project->Capabilities->App Groups. Three checkmarks should be displayed in the steps section, and the value passed in for your appGroupIdentifier should match the setting in your project file.'

    Reviewed by sunilsingh28011 at 2021-01-02 16:39
  • 13. MMWormhole use for log NetworkExtension

    I have a vpn app implemented via NetworkExtension. i use MMWormhole for Transmit message with app and Extension. but if app crash or user want feedback. i want get logs from NetworkExtension. so

    can i send logs directly from Extension to app, and save logs to app log file? because is read the code , i see writeMessageObject is write messageObject to a tempURL

    tempURL is a file path,I'm worried about performance and frequency writes。

    Reviewed by guhan121 at 2020-07-23 02:38
  • 14. Message passing is silently failing when using keyboard extension on iOS 13.5

    I've run into a weird problem with message passing between a custom keyboard app extension and its containing app.

    Following this post, I'm setting up a wormhole in both with let wormhole = MMWormhole(applicationGroupIdentifier: "group.com.mytestgroup", optionalDirectory: nil), then I do:

    • In the custom keyboard, I trigger sending a message off a keypress. The line I use to send the message is: self.wormhole.passMessageObject("the message" as NSCoding, identifier: "id1")
    • In the containing app, I create a listener with:
    self.wormhole.listenForMessage(withIdentifier: "id1", listener: { (message) -> Void in
        print("message received")
        if let messageFromKeyboard = message as? String {
            print(messageFromKeyboard)
        }
    })
    

    I would expect that after creating the listener in the containing app, a key press in the custom keyboard would cause the listener to get the message and print both "message received" and the actual message to the console. I've confirmed that this happens as expected in the xcode simulator, but it doesn't happen on my iPad...it just fails silently. No error messages....just nothing happens.

    Any idea what might be going on here? Is there any problem using MMWormhole for custom keyboards?

    Relevant info:

    • My iPad is iOS 13.5.1
    • Using MMWormhole 2.0.0 installed as a cocoapod
    • I saw the troubleshooting suggestion here but at least in my current version of xcode I see no "steps" checkmarks. Just a list of app groups.
    • Regardless, I think my app group is set up appropriately, considering the wormhole setup line let wormhole fails if I change the group id.
    • I'm using wormhole.listenForMessage as opposed to listenForMessageWithIdentifier because I get an error with the latter. Xcode suggested to change it to the former. Similar with the as NSCoding part above. I don't think these tidbits are substantial though, considering things work in sim.
    Reviewed by apollokit at 2020-07-07 06:25
  • 15. Multiple Message Passing Implementation

    Hello folks! Seems like this library is mostly unmaintained but I figured I'd open this PR for posterity sake incase anyone else needs this.

    Issue

    The default MMWormholeFileTransiting and its subclass MMWormholeCoordinatedFileTransiting both have an inherent issue where they support enqueuing multiple messages across the wormhole, BUT every time a message is enqueued, it overwrites the message payload. So, when attempting to transit N message payloads across the wormhole (similar to how NSNotificationCenter or any other message bus construct works), you get N messages but only the latest written payload.

    Solution

    This doesn't work for my use case unfortunately, so thus I present MMWormholeManifestFileTransiting for your inspection and approval. It utilizes the more modern NSFileCoordinator-based approach from MMWormholeCoordinatedFileTransiting but instead of just writing the message to disk and thus overwriting whatever is currently there, it manages a stack (NSArray) of messages that need to be sent across the wormhole which are then dispatched FILO style across the wormhole via pushing and popping the stack.

    There's a few potential improvements / optimizations to be made here:

    • Implement a FIFO queue management in addition to the existing FILO system. For my use case this would change nothing but I could see it being useful if ordering mattered if delivery is delayed (as my use case of sending data from an ActionExtension is)
    • Cleanup synchronization between messages on disk and notifications sent to the app. There's potential for drift here if for some reason the CF notification fails to deliver, as then we'll have messages enqueued in the array with no matching notification. The framework could expect the calling code to handle this case as well if that's an expected problem, which in my testing hasn't happened.
    Reviewed by msmollin at 2020-04-18 15:08
  • 16. Not working on iOS 13

    When running the code below on iOS 13:

    MMWormhole.defaultWormhole().passMessageObject(session.asDictionary() as NSCoding, identifier: MMWormholeMessageIdentifiers.session.forDirection(.send))

    I'm getting the error:

    2019-12-05 04:08:44.649148-0800 Perfect Run[4104:1225521] [WC] EXCEPTION: -[WCSession updateApplicationContext:error:]: applicationContext cannot be nil.
    2019-12-05 04:08:44.652923-0800 Perfect Run[4104:1225521] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[WCSession updateApplicationContext:error:]: applicationContext cannot be nil.'
    *** First throw call stack:
    (0x1bca46278 0x1bc76f0a4 0x1bc93bac8 0x1db7f4878 0x102e43e90 0x102e42464 0x100618864 0x1006188e4 0x100534ab8 0x1003434b8 0x10034318c 0x1003414dc 0x10034191c 0x1c0a1d870 0x1c0a1f640 0x1c0a24c08 0x1c020f2b8 0x1c0699d60 0x1c020fd9c 0x1c020f8ac 0x1c020fbc4 0x1c020f488 0x1c0213758 0x1c05cdb58 0x1c06b2f1c 0x1c02134ac 0x1c06b2e18 0x1c0213318 0x1c008bf20 0x1c008aa88 0x1c008bc58 0x1c0a22f88 0x1c05ee1c4 0x1c1aa5764 0x1c1acc538 0x1c1ab0390 0x1c1acc1f4 0x104472c88 0x1044760ac 0x1c1af2210 0x1c1af1edc 0x1c1af2404 0x1bc9c4090 0x1bc9c3fe8 0x1bc9c3780 0x1bc9be8cc 0x1bc9be16c 0x1c67e8328 0x1c0a26e1c 0x1003447bc 0x1bc849424)
    libc++abi.dylib: terminating with uncaught exception of type NSException
    

    The error the error does not occurs on iOS 12

    Reviewed by chrsp at 2019-12-05 12:12
Related tags
Easier sharing of structured data between iOS applications and share extensions
Easier sharing of structured data between iOS applications and share extensions

XExtensionItem XExtensionItem is a tiny library allowing for easier sharing of structured data between iOS applications and share extensions. It is ta

Apr 16, 2022
An open source Instapaper clone that features apps and extensions that use native UI Components for Mac and iOS.
An open source Instapaper clone that features apps and extensions that use native UI Components for Mac and iOS.

TODO: Screenshot outdated Hipstapaper - iOS and Mac Reading List App A macOS, iOS, and iPadOS app written 100% in SwiftUI. Hipstapaper is an app that

Apr 5, 2022
BFKit-Swift is a collection of useful classes, structs and extensions to develop Apps faster.
BFKit-Swift is a collection of useful classes, structs and extensions to develop Apps faster.

Features • Classes and Extensions Compatibility • Requirements • Communication • Contributing • Installing and Usage • Documentation • Changelog • Exa

Apr 28, 2022
CipherCode - iOS App to decode your secret message
CipherCode - iOS App to decode your secret message

CipherCode IOS App to decode/encode your secret message App App consist of welco

Jan 15, 2022
Generate protobuf message definitions from Swift structs

SwiftProtobufGen Generates protobuf definitions from Swift structs Building For some reason Xcode builds don't work at all but swiftpm command line bu

Nov 1, 2021
Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects

SwiftyPick ?? ?? Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects. Purpose The idea behind t

May 12, 2022
SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

Jul 6, 2021
A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.
A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.

ZamzamKit ZamzamKit is a Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and othe

Apr 14, 2022
Steps and files needed to reproduce a CSP bug in Safari Web Extensions

CSP Safari bug repro There appears to be a discrepancy between how Safari handles CSP policies for extension pages compared to how other browsers do s

Nov 6, 2021
Extensions for Swift Standard Types and Classes

Cent Cent is a library that extends certain Swift object types using the extension feature and gives its two cents to Swift language. Dollar is a Swif

Apr 18, 2022
Useful functions and extensions for sorting in Swift

SwiftSortUtils Motivation This library takes a shot at making comparing and sorting in Swift more pleasant. It also allows you to reuse your old NSSor

Feb 14, 2022
Collection of native Swift extensions to boost your development. Support tvOS and watchOS.
Collection of native Swift extensions to boost your development. Support tvOS and watchOS.

SparrowKit Collection of native Swift extensions to boost your development. Support iOS, tvOS and watchOS. If you like the project, don't forget to pu

May 13, 2022
A μframework of extensions for SequenceType in Swift 2.0, inspired by Python's itertools, Haskell's standard library, and other things.

SwiftSequence Full reference here. (If you're looking for data structures in Swift, those have been moved to here) SwiftSequence is a lightweight fram

Mar 20, 2022
Helpful extensions for iOS app development 🚀
Helpful extensions for iOS app development 🚀

ExtensionKit includes many extensions, from getting the user location with a deterministic Combine API to a shimmer loading animation, to keyboard notification updates, bottom sheet and much much more. Check out the docs below or install the library with SPM to try it out.

Apr 27, 2022
Personally useful Swift Extensions for iOS Development

Useful-Swift-Extensions Personally useful Swift Extensions for iOS Development; cobbled together from a variety of development projects and StackOverf

Dec 13, 2021
Common iOS extensions

NVExtensions Common iOS extensions. Requirement iOS 13.0+ Swift 5.5+ Dependencies SwiftDate Installation Swift Package Manager The Swift Package Manag

Feb 27, 2022
Extensions giving Swift's Codable API type inference super powers 🦸‍♂️🦹‍♀️
Extensions giving Swift's Codable API type inference super powers 🦸‍♂️🦹‍♀️

Welcome to Codextended — a suite of extensions that aims to make Swift’s Codable API easier to use by giving it type inference-powered capabilities an

May 16, 2022
A handy collection of more than 500 native Swift extensions to boost your productivity.

SwifterSwift is a collection of over 500 native Swift extensions, with handy methods, syntactic sugar, and performance improvements for wide range of

May 14, 2022
Handy Combine extensions on NSObject, including Set.
Handy Combine extensions on NSObject, including Set<AnyCancellable>.

Storable Description If you're using Combine, you've probably encountered the following code more than a few times. class Object: NSObject { var c

May 13, 2022