【问题标题】:Swift and CoreData / Data StorageSwift 和 CoreData / 数据存储
【发布时间】:2014-07-23 05:00:52
【问题描述】:

我只是在学习 Objective-C / Cocoa Touch 和 Core Data。那么,在纯 Swift 编写的 iOS 应用项目中实现数据存储的新可能性是什么?我真的很喜欢这种语言,但据我所知,所有核心数据方法都是用 Objective-C 编写的。那么核心数据类/方法会自动转换为 Swift-Code,还是我们必须将核心数据的 Objective-C 代码和其他所有内容的 Swift-Code 混合?

【问题讨论】:

    标签: ios objective-c core-data swift


    【解决方案1】:

    这就是我实现核​​心数据的方式。

    几个非常重要的注意事项:

    • 你必须将它添加到你的 NSManagedObject 类中:

      @objc(MyObject)

    • 您必须将实体名称添加到 .xcdatamodel 中的默认配置类(包括图片)

    • 你不能简单地创建一个 NSManagedObject。

      var myObject : MyObject = MyObject()
      

    你必须这样做:

    let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let context: NSManagedObjectContext = appDelegate.managedObjectContext
    let entityName: String = "MyObject"
    let myEntityDescription = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
    var myObject = MyObject(entity: myEntityDescription, insertIntoManagedObjectContext: context)
    

    这是我的 NSManagedObject。我包括了两个 fetch 方法以及一个用于对象构造的类方法。 您可能会注意到我正在利用新的枚举系统,以便我可以轻松访问我的实体名称和实体属性

    import UIKit
    import CoreData
    
    enum MyObjectPropertyList { 
        case name
        func description() -> String {
            switch self {
            case .name:
                return "name"
            }
        }
    }
    
    @objc(MyObject)
    class MyObject: NSManagedObject {
    
        @NSManaged var name: String
    
        //
        //// CREATE CLASS OBJECT
        //
    
        class func createMyObject (propertyName:MyObjectPropertyList, value:String, context: NSManagedObjectContext) -> MyObject? {
            if !value.isEmpty {
                let propertyType = propertyName.description()
    
                let entityName = "MyObject"
                let request : NSFetchRequest = NSFetchRequest(entityName: entityName)
                request.returnsObjectsAsFaults = false
                request.predicate = NSPredicate(format: "\(propertyType) = %@", value)
                var error: NSError? = nil
                var matches: NSArray = context.executeFetchRequest(request, error: &error)
    
                if (matches.count > 1) {
                    // handle error
                    return matches[0] as? MyObject
                } else if matches.count ==  0 {
                    let entityDescription = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
                    var myObject : MyObject = MyObject(entity: entityDescription, insertIntoManagedObjectContext: context)
                    myObject.name = value
                    return myObject
                }
                else {
                    println(matches[0])
                    return matches[0] as? MyObject
                }
            }
            return nil
        }
    }
    
        //
        //// FETCH REQUESTS
        //
    
        func myGeneralFetchRequest (entity : CoreDataEntities,
                                  property : MyObjectPropertyList,
                                   context : NSManagedObjectContext) -> AnyObject[]?{
    
            let entityName = entity.description()
            let propertyName = property.description()
    
            let request :NSFetchRequest = NSFetchRequest(entityName: entityName)
            request.returnsObjectsAsFaults = false
            let sortDescriptor : NSSortDescriptor = NSSortDescriptor(key: propertyName, ascending: true)
            request.sortDescriptors = [sortDescriptor]
            var error: NSError? = nil
            var matches: NSArray = context.executeFetchRequest(request, error: &error)
    
            if matches.count > 0 {
                return matches
            }
            else {
                return nil
            }
        }
    
        func myNameFetchRequest (entity : CoreDataEntities,
                               property : MyObjectPropertyList,
                                  value : String,
                                context : NSManagedObjectContext) -> AnyObject[]? {
    
            let entityName = entity.description()
            let propertyName = property.description()
    
            let request :NSFetchRequest = NSFetchRequest(entityName: entityName)
            request.returnsObjectsAsFaults = false
            request.predicate = NSPredicate(format: "\(propertyName) = %@", value)
            let sortDescriptor :NSSortDescriptor = NSSortDescriptor(key: propertyName, ascending: true)
            request.sortDescriptors = [sortDescriptor]
            var error: NSError? = nil
            var matches: NSArray = context.executeFetchRequest(request, error: &error)
    
            if matches.count > 0 {
                return matches
            }
            else {
                return nil
            }
        }
    
        //
        //// PRINT FETCH REQUEST
        //
    
        func printFetchedArrayList (myarray:AnyObject[]) {
            if myarray.count > 0 {
                println("Has \(myarray.count) object")
                for myobject : AnyObject in myarray {
                    var anObject = myobject as MyObject
                    var thename = anObject.name
                    println(thename)
                }
            }
            else {
                println("empty fetch")
            }
        }
    

    这是我的视图控制器

    import UIKit
    import CoreData
    
    enum CoreDataEntities {
        case MyObject
        func description() -> String {
            switch self {
            case .MyObject:
                return "MyObject"
            }
        }
    }
    
    class ViewController: UIViewController {
    
        //
        //// MOC
        //
    
        var managedObjectContext : NSManagedObjectContext = NSManagedObjectContext()
    
        //
        //// Text Field
        //
    
        @IBOutlet var myTextField : UITextField
    
        //
        //// BUTTONS
        //
    
        @IBAction func saveButtonPress(sender : UIButton) {
            makeEntityAction()
        }
    
        @IBAction func fetchButtonPress(sender : UIButton) {
            fetchObjectAction()
        }
    
        //
        //// ACTIONS
        //
    
        func makeEntityAction () {
            println("-- Make action --")
    
            let value:String = self.myTextField.text
            var myObject : MyObject = MyObject.createMyObject(MyObjectPropertyList.name, value : value, context: self.managedObjectContext)!
            saveContext(self.managedObjectContext)
        }
    
        func fetchObjectAction () {
            println("-- Fetch action --")
    
            if let myTotalarray = myGeneralFetchRequest(CoreDataEntities.MyObject, MyObjectPropertyList.name, self.managedObjectContext) {
                printFetchedArrayList(myTotalarray)
            }
            if let mySinglearray: AnyObject[] = myNameFetchRequest(CoreDataEntities.MyObject, MyObjectPropertyList.name, "Bill", self.managedObjectContext) {
                println("(--  --)")
                printFetchedArrayList(mySinglearray)
            }
    
        }
    
        //
        //// LOAD & SAVE
        //
    
        func loadContext () {
            let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
            let context: NSManagedObjectContext = appDelegate.managedObjectContext
            self.managedObjectContext = context
        }
    
        func saveContext (context: NSManagedObjectContext) {
            var error: NSError? = nil
            context.save(&error)
        }
    
        //
        //// LOAD
        //
    
        func myLoad () {
            loadContext ()
            println("Loaded Context")
        }
    
        //
        //// Life Cycle
        //
    
        override func viewDidLoad() {
            super.viewDidLoad()
            myLoad ()
        }
    
    }
    

    【讨论】:

    • 用户 William 在消息中留下的保留评论:您需要确保文本字段不为零,此外您检索的对象实际上具有名称字段。这可以通过传统的 if 语句方式来完成。一个例子包括: var value:String="default" if(self.myTextField.text != nil) { value=self.myTextField.text }
    【解决方案2】:

    所有的 Objective-C 框架都是 swift-ready。 Swift 友好的标头是自动生成的(按需显示),您可以从 Swift 访问任何可以从 ObjC 访问的内容。

    【讨论】:

    • 我们在哪里可以找到标题?类似于 obj-c 中的文档。
    • 查看Reference Library。所有文档都显示了使用 API 的 Swift 和 ObjC 语法。查看Using Swift with Cocoa and Objective-C 以获取有关如何混合语言的更多信息,并查看@NSManaged 属性,特别是用于处理Core Data。
    【解决方案3】:

    我已经测试过使用swift访问coredata,请访问演示代码:https://github.com/iascchen/SwiftCoreDataSimpleDemo

    【讨论】:

    • 我是否正确理解了您的文件?你没有工作演示?
    • 当然不清楚,但自己运行演示似乎确实有效。看起来@IascCHEN 使用自动生成的 Obj-C NSManagedObject 子类文件,而不是仅使用 Swift 的解决方案(我更喜欢)
    • 在Xcode 6 beta 3之后,可以生成swift NSManagedObject,但是要在swift代码中添加@objc。请检查 member.swift 文件。你可以从日志中查看运行进度。
    【解决方案4】:

    如果您想玩转 Swift 和 CoreData,我编写了一个框架,它是 CoreData 的 Active Record 风格助手。

    SuperRecord Swift Framework

    (注意:不是无耻的插件:)我实际上认为这对用户有用)。

    【讨论】:

      【解决方案5】:

      XCode 6 Beta 4 现在允许您在从数据模型生成 NSManagedObject 子类时选择 Objective C 或 Swift。

      【讨论】:

        【解决方案6】:

        这是将 CoreData 添加到 Swift 应用程序的另一种方法。 这种方法对应用程序的其余部分隐藏了 CoreData 实现细节。在应用程序中,您可以使用如下查询/更新:

        Query("Order").sort("date").fetch()
        

        或:

        let newClient = Query("Client").create() as? Client
        

        见要点:https://gist.github.com/gk11/438c3f2883c5d7c0b0d8

        【讨论】:

          猜你喜欢
          • 2014-10-24
          • 1970-01-01
          • 1970-01-01
          • 2019-02-28
          • 1970-01-01
          • 2020-03-03
          • 1970-01-01
          • 2015-02-23
          • 2011-02-03
          相关资源
          最近更新 更多