获取单个可转换属性的请求(Swift)

Posted

技术标签:

【中文标题】获取单个可转换属性的请求(Swift)【英文标题】:Fetch request on single Transformable attribute (Swift) 【发布时间】:2016-07-24 20:37:05 【问题描述】:

我有一个名为 NoteEntity 的核心数据实体(类型)。它有一个名为 noteDocument 的托管变量,它是自定义类型 NoteDocument(我的 NSDocument 的子类)。我更改了它的自动生成的 NoteEntity+Core Data Properties 类,所以它显示为

import Foundation
import CoreData

extension NoteEntity 

    @NSManaged var noteDocument: NoteDocument? // changed
    @NSManaged var belongsTo: NSSet?


所以 noteDocument 的类型是 NoteDocument 而不是 NSObject。 NoteDocument 类确实实现了 NSCoding,如下:

required convenience init(coder theDecoder: NSCoder)

    let retrievedURL = theDecoder.decodeObjectForKey("URLKey") as! NSURL
    self.init(receivedURL: retrievedURL)


func encodeWithCoder(theCoder: NSCoder)

    theCoder.encodeObject(fileURL, forKey: "URLKey")

我希望能够在具有给定 noteDocument 值的托管上下文中找到 noteEntity 实体。所以我运行这段代码(向它传递一个参数 theNote,它对应于我知道托管上下文中存在的 noteDocument):

    var request = NSFetchRequest(entityName: "NoteEntity")
    let notePredicate = NSPredicate(format: "noteDocument == %@", theNote)
    request.predicate = notePredicate

    print("Text in the NoteEntity with the NoteDocument for "+theNote.filename+":")

    do
    
        let notesGathered = try context.executeFetchRequest(request) as? [NoteEntity]

        for n in notesGathered!
        
            print (n.noteDocument!.filename)
            print (n.noteDocument!.noteText)
        
    
    catch let error as NSError
    
        print("Could not run fetch request. \(error), \(error.userInfo)")
    

但它不返回任何条目。如果我注释掉谓词,我会得到数据库中的所有 NoteEntity 值,但如果有谓词,我什么也得不到。显然,我试图在谓词中进行的搜索有问题。我认为这是因为该值是可变形的,但我不确定从那里去哪里。我知道你不能对 Transformable 数组的成员运行 fetch 请求,但是不可能对单个 Transformable 属性运行 fetch 请求吗?如果不是,还有哪些替代方案?

编辑:NoteDocument 类包含的内容远不止 NSCoding。正如我所说,它是一个 NSDocument 子类。 NSCoding 使用 URL 作为其键,因为这是 NoteDocument 类的“主键”——它是初始化类的东西。这是课程的其余部分,不包括上面的 NSCoding:

import Cocoa

class NoteDocument: NSDocument, NSCoding

var filename: String
var noteText: String
var attributes: NSDictionary?
var dateCreated: NSDate?
var dateString: String?

init (receivedURL: NSURL)

    self.filename = ""
    self.noteText = ""
    super.init()

    self.fileType = "net.daringfireball.markdown"
    self.fileURL = receivedURL

    // Try to get attributes, most importantly date-created.
    let fileManager = NSFileManager.defaultManager()
    do
    
        attributes = try fileManager.attributesOfItemAtPath(fileURL!.path!)
    
    catch let error as NSError
    
        print("The error was: "+String(error))
    

    if let dateCreated = attributes?.fileCreationDate()
    
        // print("dateCreated is "+String(dateCreated!))

        // Format the date-created to an appropriate string.
        dateString = String(dateCreated)
    
    else
    
        print("Did not find the attributes for "+filename)
    

    if let name = self.fileURL?.lastPathComponent
    
        filename = name
    
    else
    
        filename = "Unnamed File"
    

    noteText = ""

    do
    
        noteText = try NSString(contentsOfURL: self.fileURL!, encoding: NSUTF8StringEncoding) as String
    
    catch let error as NSError
    
        print("Error trying to get note file:"+String(error))
    


// MARK: - Document functions

override class func autosavesInPlace() -> Bool

    // print ("autosavesInPlace ran.")
    return true


override func dataOfType(typeName: String) throws -> NSData
        
    var outError: NSError! = NSError(domain: "Migrator", code: 0, userInfo: nil)

    // Post: Document is saved to a file specified by the user.

    outError = NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)

    if let value = self.noteText.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) 
        // Convert noteText to an NSData object and return that.
        return value
    
    print("dataOfType ran.")

    throw outError



override func readFromData(data: NSData, ofType typeName: String) throws

    // Currently unused; came free with NSDocument.
    throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)




【问题讨论】:

您要比较文档或网址吗? 我正在尝试比较 Document 对象(属于 NoteDocument 类,它是 NSDocument 的子类)。我应该相应地更改 NSCoding 吗? 你使用 SQLite 存储吗? 我相信是这样 - 目前默认的 CocoaAppCD.storedata 存储,我认为是 SQLite。 【参考方案1】:

在代码中,您表明您编码的唯一内容是 URL。在这种情况下,在实体中使用纯字符串来存储 URL 并为文档添加临时属性(或创建包装类以组合实体和文档)会更有意义并提供更多实用程序。通过这种方式,您可以在谓词中使用 URL,并且很容易从文档中构建谓词。将文档存储为可转换文件似乎对您没有任何帮助。

【讨论】:

见上面的编辑。我正在尝试存储整个文档,以便可以将对文档的更改(尤其是但不仅是 noteText 变量)保存在持久存储中(而不仅仅是文件系统)。 URL 只是我用于 NSCoding 部分的密钥。现在我很清楚这就是我的问题所在,但我不确定该怎么做。我见过的大多数 NSCoding 示例都是这样的:将单个属性作为进入 store 的键,然后保持原样。有没有更好的方法来实现可转换? 我的答案是——在可转换的核心数据中,您只能获得 NSCoding 实现所保存的内容。整个文档不会保存在持久存储中。为什么你还要保存同一事物的 2 个不同副本? 嗯,我希望基于关系数据库的持久存储的加载速度比硬盘驱动器/辅助内存快。这样我就可以检查文件系统中版本与持久存储的日期修改,并且仅在文件系统比存储中的版本更新时才从文件系统加载文档。我想如果我仍然想这样做,那么做到这一点的方法是让 NSCoding 将注释文本和日期修改变量编码为 URL 旁边的键? 是的,但核心数据存储的唯一好处是部分加载,整个数据集的加载不会更快。如果将所有数据放在同一个可转换对象中,则差异基本上为零。为了提高速度,您应该查看可以保留在内存中的内容以及使用频率较低的数据,以便在明确请求之前无需加载。 公平。没有机会对此进行测试,因为还有a bug 在此期间使程序崩溃,但我想确保获得赏金,并且您的回答是有道理的。我将尝试按照您的建议对 URL 进行编码,如果我决定确实需要将更多 Document 元素放入数据库中,那么我将在 URL 旁边编码更多变量。

以上是关于获取单个可转换属性的请求(Swift)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 Swift 的 Core Data 获取非标准(可转换)属性来更新/保存和持久化?

如何在 Swift 中将可转换属性保存到 Core Data

如何使用 Weka API 请求单个属性的输入以遍历决策树?

使用核心数据swift ios获取实体的所有属性到tableview中的行中的标签

如果我有一个加载用户对象的处理程序拦截器,将其添加到请求属性,我是不是强制转换为获取对象?

如何获取单个表格行日期索引属性索引,以便我可以提取其单元格的值?