【问题标题】:Combining queries in Realm?在领域中组合查询?
【发布时间】:2015-06-24 18:53:48
【问题描述】:

我的模型中有这两个对象:

留言

class Message: Object {
    //Precise UNIX time the message was sent
    dynamic var sentTime: NSTimeInterval = NSDate().timeIntervalSince1970
    let images = List<Image>()
}

图片

class Image: Object {
    dynamic var mediaURL: String = ""
    var messageContainingImage: Message {
        return linkingObjects(Message.self, forProperty: "images")[0]
    }
}

我想形成一个返回消息和图像的查询,消息按sentTime 排序,图像按messageContainingImage 的发送时间排序。它们将被排序在一起。

推荐的查询代码如下:

let messages = Realm().objects(Message).sorted("sentTime", ascending: true)

这将返回一个Result&lt;Message&gt; 对象。 Result 无法加入另一个结果。我的方式还有其他问题,例如,如果我可以将它们组合起来,我将如何进行排序。

其他想法:

  • 我还可以向 Image 添加一个名为 sentTime 的属性,然后一旦将它们组合起来,我就可以在它们两个上调用该属性。
  • 我可以将它们都从已发送时间的类型中创建为子类。问题是,执行 Realm().objects(Message) 只会返回消息,而不是消息的子类。

我怎样才能做到这一点?

我的最终目标是在表格视图中显示这些消息和图像结果,将消息与其附加图像分开。

【问题讨论】:

    标签: ios database swift realm


    【解决方案1】:

    我认为,继承在这里不是正确的解决方案,这会通过使您的对象架构复杂化而引入更多的缺点,而不是为您的用例带来价值。

    让我们回到您所写的是您的最终目标:我猜您希望在一个表格视图中将消息和图像一起显示为单独的行,其中图像跟随它们的消息。我理解正确吗?

    您不需要对两者都进行排序,对消息进行排序并以合适的方式访问它们及其图像将确保所有内容都正确排序。主要挑战更多的是如何将这种二维数据结构作为一维序列进行枚举/随机访问。

    根据您查询的数据量,您必须决定是否可以采用一种简单的方法,将它们一次全部保存在内存中,或者在结果之上引入一个视图对象,该对象负责访问所有对象按顺序排列。

    第一个解决方案可能如下所示:

    let messages = Realm().objects(Message).sorted("sentTime", ascending: true)
    array = reduce(messages, [Object]()) { (var result, message) in
                result.append(message)
                result += map(message.images) { $0 }
                return result
            }
    

    虽然后一种解决方案更复杂,但可能如下所示:

    // Let you iterate a list of nodes with their related objects as:
    //   [a<list: [a1, a2]>, b<list: [b1, b2, b3]>]
    // in pre-order like:
    //   [a, a1, a2, b, b1, b2, b3]
    // where listAccessor returns the related objects of a node, e.g.
    //   listAccessor(a) = [a1, a2]
    //
    // Usage:
    //    class Message: Object {
    //        dynamic var sentTime = NSDate()
    //        let images = List<Image>()
    //    }
    //
    //    class Image: Object {
    //        …
    //    }
    //
    //   FlattenedResultsView(Realm().objects(Message).sorted("sentTime"), listAccessor: { $0.images })
    //
    class FlattenedResultsView<T: Object, E: Object> : CollectionType {
        typealias Index = Int
        typealias Element = Object
    
        let array: Results<T>
        let listAccessor: (T) -> (List<E>)
        var indexTransformVectors: [(Int, Int?)]
        var notificationToken: NotificationToken? = nil
    
        init(_ array: Results<T>, listAccessor: T -> List<E>) {
            self.array = array
            self.listAccessor = listAccessor
            self.indexTransformVectors = FlattenedResultsView.computeTransformVectors(array, listAccessor)
            self.notificationToken = Realm().addNotificationBlock { note, realm in
                self.recomputeTransformVectors()
            }
        }
    
        func recomputeTransformVectors() {
            self.indexTransformVectors = FlattenedResultsView.computeTransformVectors(array, listAccessor)
        }
    
        static func computeTransformVectors(array: Results<T>, _ listAccessor: T -> List<E>) -> [(Int, Int?)] {
            let initial = (endIndex: 0, array: [(Int, Int?)]())
            return reduce(array, initial) { (result, element) in
                var array = result.array
                let list = listAccessor(element)
    
                let vector: (Int, Int?) = (result.endIndex, nil)
                array.append(vector)
    
                for i in 0..<list.count {
                    let vector = (result.endIndex, Optional(i))
                    array.append(vector)
                }
    
                return (endIndex: result.endIndex + 1, array: array)
            }.array
        }
    
        var startIndex: Index {
            return indexTransformVectors.startIndex
        }
    
        var endIndex: Index {
            return indexTransformVectors.endIndex
        }
    
        var count: Int {
            return indexTransformVectors.count
        }
    
        subscript (position: Index) -> Object {
            let vector = indexTransformVectors[position]
            switch vector {
            case (let i, .None):
                return array[i]
            case (let i, .Some(let j)):
                return listAccessor(array[i])[j]
            }
        }
    
        func generate() -> GeneratorOf<Object> {
            var arrayGenerator = self.array.generate()
            var lastObject: T? = arrayGenerator.next()
            var listGenerator: GeneratorOf<E>? = nil
            return GeneratorOf<Object> {
                if listGenerator != nil {
                    let current = listGenerator!.next()
                    if current != nil {
                        return current
                    } else {
                        // Clear the listGenerator to jump back on next() to the first branch
                        listGenerator = nil
                    }
                }
                if let currentObject = lastObject {
                    // Get the list of the currentObject and advance the lastObject already, next
                    // time we're here the listGenerator went out of next elements and we check
                    // first whether there is anything on first level and start over again.
                    listGenerator = self.listAccessor(currentObject).generate()
                    lastObject = arrayGenerator.next()
                    return currentObject
                } else {
                    return nil
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多