Super awesome Swift minion for Core Data (iOS, macOS, tvOS)

Related tags

UI AERecord
Overview

Swift 4.2 Platforms iOS | watchOS | tvOS | macOS CocoaPods Carthage Swift Package Manager License MIT

⚠️ Since this repository is going to be archived soon, I suggest migrating to NSPersistentContainer instead (available since iOS 10). For other convenience helpers, beside managing stack, I'm currently just using this.

AERecord

Super awesome Swift minion for Core Data (iOS, macOS, tvOS)

I made this for personal use, but feel free to use it or contribute. For more examples check out Sources and Tests.

Index

Intro

AECoreDataUI was previously part of AERecord, so you may want to check that also.

Why do we need yet another one Core Data wrapper? You tell me!
Inspired by many different (spoiler alert) magical solutions, I wanted something which combines complexity and functionality just about right. All that boilerplate code for setting up of Core Data stack, passing the right NSManagedObjectContext all accross the project and different threads, not to mention that boring NSFetchRequest boilerplates for any kind of creating or querying the data - should be more simple with this.

Features

  • Create default or custom Core Data stack (or more stacks) easily accessible from everywhere
  • Have main and background contexts, always in sync, but don't worry about it
  • CRUD data in many ways with generic one liners
  • iCloud support
  • Covered with unit tests
  • Covered with inline docs

Usage

You may see this demo project for example.

Create Core Data stack

Almost everything in AERecord is made with 'optional' parameters (which have default values if you don't specify anything).
So you can load (create if doesn't already exist) CoreData stack like this:

do {
    try AERecord.loadCoreDataStack()
} catch {
    print(error)
}

or like this:

let myModel: NSManagedObjectModel = AERecord.modelFromBundle(for: MyClass.self)
let myStoreType = NSInMemoryStoreType
let myConfiguration = ...
let myStoreURL = AERecord.storeURL(for: "MyName")
let myOptions = [NSMigratePersistentStoresAutomaticallyOption : true]
do {
    try AERecord.loadCoreDataStack(managedObjectModel: myModel, storeType: myStoreType, configuration: myConfiguration, storeURL: myStoreURL, options: myOptions)
} catch {
    print(error)
}

or any combination of these.

If for any reason you want to completely remove your stack and start over (separate demo data stack for example) you can do it as simple as this:

do {
    try AERecord.destroyCoreDataStack() // destroy default stack
} catch {
    print(error)
}

do {
    let demoStoreURL = AERecord.storeURL(for: "Demo")
    try AERecord.destroyCoreDataStack(storeURL: demoStoreURL) // destroy custom stack
} catch {
    print(error)
}

Similarly you can delete all data from all entities (without messing with the stack) like this:

AERecord.truncateAllData()

Context operations

Context for current thread (Context.default) is used if you don't specify any (all examples below are using Context.default).

// get context
AERecord.Context.main // get NSManagedObjectContext for main thread
AERecord.Context.background // get NSManagedObjectContext for background thread
AERecord.Context.default // get NSManagedObjectContext for current thread

// execute NSFetchRequest
let request = ...
let managedObjects = AERecord.execute(fetchRequest: request) // returns array of objects

// save context
AERecord.save() // save default context
AERecord.saveAndWait() // save default context and wait for save to finish

// turn managed objects into faults (you don't need this often, but sometimes you do)
let objectIDs = ...
AERecord.refreshObjects(with: [objectIDs], mergeChanges: true) // turn objects for given IDs into faults
AERecord.refreshRegisteredObjects(mergeChanges: true) // turn all registered objects into faults

Easy Queries

Easy querying helpers are created as NSManagedObject extension.
All queries are called on generic NSManagedObject, and Context.default is used if you don't specify any (all examples below are using Context.default). All finders have optional parameter for NSSortDescriptor which is not used in these examples. For even more examples check out unit tests.

General

If you need custom NSFetchRequest, you can use createPredicate(with:) and createFetchRequest(predicate:sortdDescriptors:), tweak it as you wish and execute with AERecord.

// create request for any entity type
let attributes = ...
let predicate = NSManagedObject.createPredicate(with: attributes)
let sortDescriptors = ...
let request = NSManagedObject.createFetchRequest(predicate: predicate, sortDescriptors: sortDescriptors)

// set some custom request properties
request.someProperty = someValue

// execute request and get array of entity objects
let managedObjects = AERecord.execute(fetchRequest: request)

Of course, all of the often needed requests for creating, finding, counting or deleting entities are already there, so just keep reading.

Create

NSManagedObject.create() // create new object

let attributes = ...
NSManagedObject.create(with: attributes) // create new object and sets it's attributes

NSManagedObject.firstOrCreate(with: "city", value: "Belgrade") // get existing object (or create new if it doesn't already exist) with given attribute

let attributes = ...
NSManagedObject.firstOrCreate(with: attributes) // get existing object (or create new if it doesn't already exist) with given attributes

Find first

NSManagedObject.first() // get first object

let predicate = ...
NSManagedObject.first(with: predicate) // get first object with predicate

NSManagedObject.first(with: "bike", value: "KTM") // get first object with given attribute name and value

let attributes = ...
NSManagedObject.first(with: attributes) // get first object with given attributes

NSManagedObject.first(orderedBy: "speed", ascending: false) // get first object ordered by given attribute name

Find all

NSManagedObject.all() // get all objects

let predicate = ...
NSManagedObject.all(with: predicate) // get all objects with predicate

NSManagedObject.all(with: "year", value: 1984) // get all objects with given attribute name and value

let attributes = ...
NSManagedObject.all(with: attributes) // get all objects with given attributes

Delete

let managedObject = ...
managedObject.delete() // delete object (call on instance)

NSManagedObject.deleteAll() // delete all objects

NSManagedObject.deleteAll(with: "fat", value: true) // delete all objects with given attribute name and value

let attributes = ...
NSManagedObject.deleteAll(with: attributes) // delete all objects with given attributes

let predicate = ...
NSManagedObject.deleteAll(with: predicate) // delete all objects with given predicate

Count

NSManagedObject.count() // count all objects

let predicate = ...
NSManagedObject.count(with: predicate) // count all objects with predicate

NSManagedObject.count(with: "selected", value: true) // count all objects with given attribute name and value

let attributes = ...
NSManagedObject.count(with: attributes) // count all objects with given attributes

Distinct

do {
    try NSManagedObject.distinctValues(for: "city") // get array of all distinct values for given attribute name
} catch {
    print(error)
}

do {
    let attributes = ["country", "city"]
    try NSManagedObject.distinctRecords(for: attributes) // get dictionary with name and values of all distinct records for multiple given attributes
} catch {
    print(error)
}

Auto Increment

If you need to have auto incremented attribute, just create one with Int type and get next ID like this:

NSManagedObject.autoIncrementedInteger(for: "myCustomAutoID") // returns next ID for given attribute of Integer type

Turn managed object into fault

NSFetchedResultsController is designed to watch only one entity at a time, but when there is a bit more complex UI (ex. showing data from related entities too), you sometimes have to manually refresh this related data, which can be done by turning 'watched' entity object into fault. This is shortcut for doing just that (mergeChanges parameter defaults to true). You can read more about turning objects into faults in Core Data documentation.

let managedObject = ...
managedObject.refresh() // turns instance of managed object into fault

Batch update

Batch updating is the 'new' feature from iOS 8. It's doing stuff directly in persistent store, so be carefull with this and read the docs first. Btw, NSPredicate is also optional parameter here.

NSManagedObject.batchUpdate(properties: ["timeStamp" : NSDate()]) // returns NSBatchUpdateResult?

NSManagedObject.objectsCountForBatchUpdate(properties: ["timeStamp" : NSDate()]) // returns count of updated objects

NSManagedObject.batchUpdateAndRefreshObjects(properties: ["timeStamp" : NSDate()]) // turns updated objects into faults after updating them in persistent store

Installation

License

AERecord is released under the MIT license. See LICENSE for details.

Comments
  • Swift 2.0 support

    Swift 2.0 support

    Thanks for creating and sharing this library with the world, it's proving quite helpful.

    What plans (if any) do you have for supporting Swift 2.0?

    Thanks.

    opened by jamesbebbington 7
  • I guess, Stack class name conflicting in my Project with some other framework

    I guess, Stack class name conflicting in my Project with some other framework

    Also another issue: /Users/.../Pods/AERecord/Sources/AERecord.swift:69:82: Class 'Stack' is internal and cannot be referenced from a default argument value (multiple time this issue for different methods/properties) /Users/.../Pods/AERecord/Sources/Query.swift:581:71: Static let 'defaultPredicateType' is private and cannot be referenced from a default argument value (multiple time this issue for different methods/properties)

    I tested your classes in your test project AECoreDataDemo, and its working fine. Suggest me what I do?

    opened by ods2-hamid 3
  • Add Dynamic Framework support & Carthage support

    Add Dynamic Framework support & Carthage support

    This pull request adds iOS, tvOS and OSX targets with shared schemes (for installation via Carthage) and configures those to work as a dynamic framework. Also a section to the README about Carthage installation was added.

    This should solve #8.

    opened by Jeehut 3
  • Swift2

    Swift2

    Hello @tadija, I've migrated the AERecord code base to swift 2.0 syntax. The migration tool wasn't very helpful here because we had a lot of do try catch usecases to handle. I've also removed a few as? conversions because most CoreData methods uses the proper classes now (rather than AnyObject).

    Let me know if you have any questions or feedback.

    opened by apouche 3
  • I'm getting this error on latest version of AERecord

    I'm getting this error on latest version of AERecord

    I did a pod update and i started facing this error. This problem is on 3.0.0 on 2.1.0 it works fine

     private class func _firstOrCreateWithAttributes<T>(attributes: [String : AnyObject], predicateType: NSCompoundPredicateType = defaultPredicateType, context: NSManagedObjectContext = AERecord.defaultContext) -> T {
            let predicate = createPredicateForAttributes(attributes, predicateType: predicateType)
            let request = createFetchRequest(predicate: predicate)
            request.fetchLimit = 1
            let objects = AERecord.executeFetchRequest(request, context: context)
    
            return (objects.first ?? createWithAttributes(attributes, context: context)) as! T //Here i get the error
        }
    

    ERROR

    Could not cast value of type 'NSManagedObject_AccountDetails_' (0x7fd43ae881b0) to 'FeedbackChamp.AccountDetails' (0x1081b1220).

    MY CODE

    AccountDetails.firstOrCreateWithAttributes(["data" : readableJSON["result"]["hoteladded"].bool! ? 1 : 0, "detailName": "num_hotels"])
    
    AccountDetails.firstOrCreateWithAttributes(["data" : readableJSON["result"]["num_restaurants"].int!, "detailName": "num_restaurants"])
    
    AERecord.saveContextAndWait()
    
    

    Please fix it as soon as posible

    opened by O-mkar 2
  • Updated README to reflect correct delete function

    Updated README to reflect correct delete function

    I believe the correct delete function is model.deleteFromContext() rather than model.delete() where model is an instantiated NSManagedObject subclass. I looked through the source to find a reference to delete() and deleteFromContext() was the closest I came to finding something similar.

    If you wanted to implement the delete() function for simplicities sake, you could just map it directly to deleteFromContext() given that the context var is optional and automatically assigned to the default context if not set.

    opened by maxkramer 2
  • Generic version of methods for creating and finding

    Generic version of methods for creating and finding

    In order to be able to write

    let user: User = User.firstOrCreateWithAttribute("id", value: 123)
    

    or

    func newUser() -> User {
        return User.firstOrCreateWithAttribute("id", value: 123)
    }
    

    instead of

    let user = User.firstOrCreateWithAttribute("id", value: 123) as! User
    

    or

    func newUser() -> User {
        return User.firstOrCreateWithAttribute("id", value: 123) as! User
    }
    
    opened by kafejo 2
  • tvOS support

    tvOS support

    I've updated podspec file and added support for specifying NSSearchPathDirectory for method storeURLForName. The reason is that app cannot access Documents directory on real device, and CachesDirectory must be used.

    opened by jakubknejzlik 2
  • Property suspendAutomaticTrackingOfChangesInManagedObjectContext is private

    Property suspendAutomaticTrackingOfChangesInManagedObjectContext is private

    I don't know if I'm missing the point here, but suspendAutomaticTrackingOfChangesInManagedObjectContext is definitely marked as private and therefore can not be changed from anywhere outside the AERecird.swift file.

    opened by marioradonic 2
  • Swift 1.2 Support

    Swift 1.2 Support

    Hi,

    is there any chance of this (and AEXML) getting updated to Swift 1.2? All the other frameworks i am using already have a 1.2 branch. If there is no plan to do this i would it myself but otherwise it would be a waste of time :).

    opened by Harper04 2
  • Download and Save Async Data in Multiple Threads

    Download and Save Async Data in Multiple Threads

    hey Marko,

    i have an issue and i-m thinking that i doing something wrong with saving or creating/mapping CoreDataModels while getting data from a Webservice. Situation:

    1. I download from a Webservice all users cardboxes and serialize the Json into an DTO Object and then map the DTO to the CoreData DBOCardBoxModel
    2. ForEach downloaded and mapped Cardbox download the Cards async 2.1) When the Api Call is finished, serialize the Json into a DTO Object 2.1.1) Then i want create a new CoreDataModel when the DTO.cardNbr not exists, else get first and map then the properties from the dto to dbo 2.1.2) In the Mapper.Map(dto->dbo) i want to map all the properties and set relations, so in example a card can have multiple choice answers, so i want to create them and add this relation to the card

    Exception throw at the firstOrCreateWithAttributes methode when my call was for example 25 times called, when it called 5 times the exception didnt throw. I think it is because the NSManagementObjectContext is not on each thread, how can i handle this?

    Here is some of my Code: I using the following extensions:

    • Api: http://vluxe.io/swifthttp.html
    • JSON serialize: https://github.com/daltoniam/JSONJoy-Swift

    Another question from me is where i place my the Save funktion? I¥m not shure about this. 1.) The Api Call that will call 25 Times: (the self.saveDB will call the saveAndWait(default) funktion)

    public func ActiveCardBoxesById(dboCardBoxes : Array<String>){
            //let operationQueue = NSOperationQueue()
            //operationQueue.maxConcurrentOperationCount = dboCardBoxes.count
            for cardBox in dboCardBoxes {
                if self.CanSendRequest() {
                    var request = self.CreateBaseRequest()
                    request.requestSerializer.headers["clientid"] = self.UniqueId
                    request.GET("/cardbox/\(cardBox)/cards", parameters: nil, success: {(response: HTTPResponse) -> Void in
                        if (response.responseObject != nil) {
                            //TODO
                            let dtoCards = Cards(JSONDecoder(response.responseObject!))
                            for dtoCard in dtoCards.cards! {
                                var dboCard = DBOCard.firstOrCreateWithAttribute("cardNbr", value: dtoCard.cardNbr!) as DBOCard
                                Mapper.Map(dtoCard, dbo: dboCard)
                            }
    
                            self.dataDelegate?.ConfirmLastSyncCardBox!()
                            self.logger.info("ConfirmLastSyncCardBox \(cardBox)")
                        }
                        }, failure: {(error: NSError, response: HTTPResponse?) -> Void in
                            self.logger.error("Getting ActiveCardboxesById throw error : \(error)")
                            self.baseDelegate?.ErrorInWebService(error)
                    })
    
    
                }
                else {
                    logger.warn("Can not communicate with API")
                    self.baseDelegate?.ErrorSendingRequest()
                }
            }
            self.saveDB()
    
        }
    
    

    2.) This is the Mapper.Map methode: (the self.saveDB will call the saveAndWait(default) funktion)

    class func Map(dto : DTOCard, dbo : DBOCard) -> DBOCard {
            if let cardNbr = dto.cardNbr {
                dbo.setValue(cardNbr, forKey: "cardNbr")
            }
            if let cardBoxNbr = dto.cardBoxNbr {
                dbo.setValue(cardBoxNbr, forKey: "cardBoxNbr")
            }
            if let daystowait = dto.daystowait {
                dbo.setValue(daystowait, forKey: "daystowait")
            }
            if let delay = dto.delay {
                dbo.setValue(delay, forKey: "delay")
            }
            if let favorite = dto.favorite {
                dbo.setValue(favorite, forKey: "favorite")
            }
            if let knownInPlannedRow = dto.knownInPlannedRow {
                dbo.setValue(knownInPlannedRow, forKey: "knownInPlannedRow")
            }
            if let knownInRow = dto.knownInRow {
                dbo.setValue(knownInRow, forKey: "knownInRow")
            }
            if let lastPlannedPlayed = dto.lastPlannedPlayed {
                dbo.setValue(lastPlannedPlayed, forKey: "lastPlannedPlayed")
            }
            if let lastPlayed = dto.lastPlayed {
                dbo.setValue(lastPlayed, forKey: "lastPlayed")
            }
            if let multipleChoice = dto.multipleChoice {
                dbo.setValue(multipleChoice, forKey: "multipleChoice")
            }
            if let timesKnown = dto.timesKnown {
                dbo.setValue(timesKnown, forKey: "timesKnown")
            }
            if let timesNotKnown = dto.timesNotKnown {
                dbo.setValue(timesNotKnown, forKey: "timesNotKnown")
            }
            if let selectedForLearning = dto.selectedForLearning {
                dbo.setValue(selectedForLearning, forKey: "selectedForLearning")
            }
            if let delete = dto.delete {
                dbo.setValue(delete, forKey: "delete")
            }
            if let answer = dto.answer {
                dbo.setValue(answer, forKey: "answer")
            }
            if let answerImage = dto.answerImage {
                dbo.setValue(answerImage, forKey: "answerImage")
            }
            if let answerPureText = dto.answerPureText {
                dbo.setValue(answerPureText, forKey: "answerPureText")
            }
            if let question = dto.question {
                dbo.setValue(question, forKey: "question")
            }
            if let questionImage = dto.questionImage {
                dbo.setValue(questionImage, forKey: "questionImage")
            }
            if let questionPureText = dto.questionPureText {
                dbo.setValue(questionPureText, forKey: "questionPureText")
            }
    
            if let dtoMultipleChoices = dto.multipleChoiceCards {
                var counter = 1
                for dtoMultipleChoice in dtoMultipleChoices {
                    var acessableOrderIndex = counter
                    if let orderIndex = dtoMultipleChoice.orderIndex {
                        acessableOrderIndex = orderIndex
                    }
                    //TODO LOOK FIRST FOR CARDID AND ORDERINDEX
                    let predicate = NSPredicate(format: "cardId = \(dtoMultipleChoice.cardId! + counter) AND orderIndex = \(acessableOrderIndex)")
                    var mappedMultipleChoice : DBOMultipleChoice
                    if let existingDboMultipleChoice = DBOMultipleChoice.firstWithPredicate(predicate!) as? DBOMultipleChoice {
                        mappedMultipleChoice = self.Map(dtoMultipleChoice, dbo: existingDboMultipleChoice)
                        mappedMultipleChoice.setValue(acessableOrderIndex, forKey: "orderIndex")
                    }
                    else {
                        var dboMultipleChoice = DBOMultipleChoice.firstOrCreateWithAttribute("cardId", value: dtoMultipleChoice.cardId! + counter) as DBOMultipleChoice
                        mappedMultipleChoice = self.Map(dtoMultipleChoice, dbo: dboMultipleChoice)
                        mappedMultipleChoice.setValue(acessableOrderIndex, forKey: "orderIndex")
                    }
    
                    dbo.addMultipleChoice(mappedMultipleChoice)
                }
                counter = 1
            }
            if let dtoCategories = dto.categories {
                for dtoCategory in dtoCategories {
                    var dboCategory = DBOCategory.firstOrCreateWithAttribute("categoryId", value: dtoCategory.categoryId!) as DBOCategory
                    var mappedCategory = self.Map(dtoCategory, dbo: dboCategory)
                    mappedCategory.addCard(dbo)
                    //add category to card
                    dbo.addCategorie(mappedCategory)
                    //add card to category
    
                }
            }
    //        //get cardbox and add card
            if let dboCardBox = DBOCardBox.firstWithAttribute("cardBoxNbr", value: "\(dbo.cardBoxNbr)") as? DBOCardBox {
                //we have an cardbox
                dboCardBox.addCard(dbo)
                dbo.cardInCardBox = dboCardBox
            }
            self.save()
            return dbo
        }
    

    Exceptions sometimes dangling with reference Dangling reference to an invalid object.=null, NSValidationErrorValue

    Or Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x7fc1aa487870> was mutated while being enumerated.'

    XCode Version: 6.1

    opened by kheinrich188 2
  • Could you give me some tips to the crash `*** Collection <__NSCFSet: 0x28355f810> was mutated while being enumerated.`

    Could you give me some tips to the crash `*** Collection <__NSCFSet: 0x28355f810> was mutated while being enumerated.`

    the code is:

        func conversation(whereChatId: String) -> Conversation? {
            guard AERecord.Context.default.persistentStoreCoordinator != nil else {
                return nil
            }
            let predicate = NSPredicate.init(format: "chatId=%@", whereChatId)
            let con = Conversation.first(with: predicate)
            return con
        }
    

    the crash is:

    *** Collection <__NSCFSet: 0x28355f810> was mutated while being enumerated.
    ClouderWork + 8451948
    

    I have got this error some times in my project using AERecord, would you please help me to fix it? I can't fix it by myself, I need your help! Very thanks!

    opened by Insfgg99x 0
  • How to do this in AERecord

    How to do this in AERecord

    Sum a property:

        func totalUnreadCount(whereParentChatId: String?) -> Int {
            let req = NSFetchRequest<NSDictionary>.init(entityName: Conversation.entityName())
            if let parentChatId = whereParentChatId {
                req.predicate = NSPredicate.init(format: "parentChatId=%@", parentChatId)
            } else {
                req.predicate = NSPredicate.init(format: "parentChatId = nil")
            }
            let expressDescription = NSExpressionDescription.init()
            let express = NSExpression.init(format: "@sum.unreadCount")
            expressDescription.expression = express
            expressDescription.name = "total"
            expressDescription.expressionResultType = .integer32AttributeType
            req.propertiesToFetch = [expressDescription]
            req.resultType = .dictionaryResultType
            var count = 0
            dbContext().performAndWait {
                let result = try? dbContext().fetch(req)
                if let total = result?.first?["total"] as? Int {
                    count = total
                }
            }
            return count
        }
    
    opened by Insfgg99x 0
  • iCloud support

    iCloud support

    Hi,

    In the readme it is mentioned that AERecord supports iCloud. Besides notification references in the code, I could not find how to set up CloudKit syncing.

    Is there any documentation or references regarding iCloud sync?

    question 
    opened by wousser 0
  • Question: mergePolicy

    Question: mergePolicy

    I've tried setting the mergePolicy by loading AERecord with the myOptions parameters, but the mergePolicy option or configuration is not read correctly.

    Currently I'm using this code to set the mergePolicy, is this the best (or only) way to do this?

    AERecord.Context.default.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy AERecord.Context.background.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy AERecord.Context.main.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

    Full loading code:

    ` let myOptions = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption : true] do { try AERecord.loadCoreDataStack(options: myOptions) AERecord.Context.default.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy AERecord.Context.background.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy AERecord.Context.main.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

    } catch { debugPrint(error) } `

    help wanted 
    opened by wousser 0
  • EXC_BAD_INSTRUCTION DispatchQueue

    EXC_BAD_INSTRUCTION DispatchQueue

    If I want to create an NSManagedObject in a background thread than EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode=0x0) arise.

    @discardableResult class func create(in context: NSManagedObjectContext = AERecord.Context.default) -> Self { let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: context)! let object = self.init(entity: entityDescription, insertInto: context) // error line Line 104 in Query.swift return object }

    Part of my code: DispatchQueue.global(qos: .background).async{ let model = Model.create() }

    Do you know what's going wrong? Thank you for your efforts

    help wanted 
    opened by JohnDevC 0
Owner
Marko Tadić
keep it simple
Marko Tadić
🔍 Awesome fully customize search view like Pinterest written in Swift 5.0 + Realm support!

YNSearch + Realm Support Updates See CHANGELOG for details Intoduction ?? Awesome search view, written in Swift 5.0, appears search view like Pinteres

Kyle Yi 1.2k Dec 17, 2022
🐝 Super ultra drawer view

UltraDrawerView let headerView = HeaderView() headerView.translatesAutoresizingMaskIntoConstraints = false headerView.heightAnchor.constraint(equalToC

Ilya Lobanov 205 Dec 14, 2022
A super lightweight popView.

SNAugusPopView Features High performance: The library's dependencies all use system libraries and files , only a instance global. Automatic layout: Th

Augus 11 Sep 1, 2022
A collection of awesome loading animations

NVActivityIndicatorView ⚠️ Check out LoaderUI (ready to use with Swift Package Mananger supported) for SwiftUI implementation of this. ?? Introduction

Vinh Nguyen 10.3k Dec 27, 2022
SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

Aben 13 Nov 17, 2021
List tree data souce to display hierachical data structures in lists-like way. It's UI agnostic, just like view-model and doesn't depend on UI framework

SwiftListTreeDataSource List tree data souce to display hierachical data structures in lists-like way. It's UI agnostic, just like view-model, so can

Dzmitry Antonenka 26 Nov 26, 2022
Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle.

Twinkle ✨ Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle. This library creates several CAEmitterLayers and animate

patrick piemonte 600 Nov 24, 2022
Basic iOS app to track stocks (data from Finnhub, Tiingo, or IEX Cloud)

Basic iOS app to track stocks (data from Finnhub, Tiingo, or IEX Cloud)

null 33 Dec 21, 2022
A fancy hexagonal layout for displaying data like your Apple Watch

Hexacon is a new way to display content in your app like the Apple Watch SpringBoard Highly inspired by the work of lmmenge. Special thanks to zenly f

Gautier Gédoux 340 Dec 4, 2022
Beautiful animated placeholders for showing loading of data

KALoader Create breautiful animated placeholders for showing loading of data. You can change colors like you want. Swift 4 compatible. Usage To add an

Kirill Avery 105 May 2, 2022
Create SwiftUI Views with any data

Create SwiftUI Views with any data

Zach Eriksen 20 Jun 27, 2022
A multi-platform SwiftUI component for tabular data

SwiftTabler A multi-platform SwiftUI component for tabular data. NOTE this component is BRAND NEW and under active development. If you need stability,

OpenAlloc 45 Jan 3, 2023
High performance Swift treemap layout engine for iOS and macOS.

Synopsis YMTreeMap is a high performance treemap layout engine for iOS and macOS, written in Swift. The input to YMTreeMap is a list of arbitrary numb

Yahoo 118 Jan 3, 2023
Demonstration of LegoArtFilter for iOS/macOS

LegoArtFilterDemo Demonstration of LegoArtFilter for iOS/macOS. This project runs on both iOS (14≤) and macOS (11≤). Libraries LegoColors LegoArtFilte

Takuto NAKAMURA (Kyome) 1 Oct 16, 2021
Create macOS apps with Swift packages instead of Xcode projects

Swift Bundler A Swift Package Manager wrapper that allows the creation of MacOS apps with Swift packages instead of Xcode projects. My motivation is t

null 182 Dec 25, 2022
Circular progress indicator for your macOS app

CircularProgress Circular progress indicator for your macOS app This package is used in production by apps like Gifski and HEIC Converter. Requirement

Sindre Sorhus 520 Jan 3, 2023
Programmatic UI for macOS

Description: Programmatic UI Framework for macOS. Swift handles app logic, CSS/SVG handles design and JSON handles struture. Installation: Step 1: Add

André J 860 Dec 18, 2022
⚙ Add a preferences window to your macOS app in minutes

Preferences Add a preferences window to your macOS app in minutes Just pass in some view controllers and this package will take care of the rest. Requ

Sindre Sorhus 1.2k Jan 6, 2023
A window arrangement manager for macOS like BetterSnapTool and Magnet

A window arrangement manager for macOS like BetterSnapTool and Magnet. You can split the foremost window to the left half of the screen, the left two-thirds, etc.

Takuto NAKAMURA (Kyome) 65 Dec 9, 2022