任何想法为何此过滤器无法正常工作?
for item in activeItems {
print("item.product: \(item.product), \(item.spaceRequired)")
}
返回
item.product: nil, 40.0
过滤产品为零的地方
let f1 = activeItems.filter{$0.product != nil}
print("f1: \(f1)")
print("f1.count: \(f1.count)")
返回零计数,但数组似乎仍然包含一个项目
f1: LazyFilterSequence<Results<AssortmentItem>>(_base: Results<AssortmentItem> <0x109ce2c90> (
[0] AssortmentItem {
...
f1.count: 0
然后仅过滤并映射spaceRequired
let f11 = f1.filter{$0.product!.isProduct == true}.map({$0.spaceRequired})
print("f11: \(f11)")
使用单个项目返回相同的数组
f11: LazyMapSequence<LazyFilterSequence<Results<AssortmentItem>>, Double>(_base: Swift.LazyFilterSequence<RealmSwift.Results<Merchandise_Manager.AssortmentItem>>(_base: Results<AssortmentItem> <0x109ce2c90> (
[0] AssortmentItem {
然后尝试减少崩溃
let w = f11.reduce(0,+)
这似乎可以解决问题
let width = Array(activeItems.filter{$0.product != nil}).filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
这是Swift 5还是Realm中的错误?
编辑:看来这是Realm处理事物中的错误。
下面需要清除的是一组更完整的Realm对象。
import Foundation
import RealmSwift
let activeDate: NSDate = Date() as NSDate
let defaultWidth: Double = 40.0
class MyObject: Object {
@objc dynamic var number: Int = 0
@objc dynamic var name: String?
let items = List<ChildObject>()
}
extension MyObject {
var activeItems: Results<ChildObject> {
let activeDate = activeDate // Some globally defined value
let active = items.filter("startDate <= %@ && (endDate >= %@ || endDate == nil)", activeDate, activeDate).sorted(byKeyPath: "number")
return active
}
/// Works Correctly
var totalWidth: Double {
let width = Array(activeItems.filter{$0.product != nil}).filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
let width2 = Array(activeItems.filter{$0.product == nil}.map({$0.spaceRequired})).reduce(0,+)
return width+width2
}
/// Crashes
var totalWidth: Double {
let width = activeItems.filter{$0.product != nil}.filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
let width2 = activeItems.filter{$0.product == nil}.map({$0.spaceRequired}).reduce(0,+)
return width+width2
}
}
class ChildObject: Object {
@objc dynamic var parent: MyObject?
@objc dynamic var number: Int = 0
@objc dynamic var product: Product?
@objc dynamic var name: String?
@objc dynamic var spaceRequired: Double = 40.0
@objc dynamic var startDate: NSDate?
@objc dynamic var endDate: NSDate?
}
extension ChildObject {
var spaceRequired: Double {
if let p = product {
return p.width
} else {
return defaultWidth
}
}
}
class Product: Object {
@objc dynamic var isProduct: Bool = false
@objc dynamic var width: Double = 30.0
}
答案 0 :(得分:0)
f1
的计数为0
,因此映射不起作用。
您可以按以下方式优化宽度计算
let width = activeItems
.filter { $0.product?.isProduct ?? false }
.map { $0.spaceRequired }
.reduce(0,+)
答案 1 :(得分:0)
这里有两个问题,但主要问题是Realm Results正在实时更新;当您可以使用Swifty
过滤数据时let f1 = activeItems.filter{$0.product != nil}
由于Realm不知道要过滤哪些项目,因此它将给出间歇性结果。.filter {不是Realm函数,Realm不知道在结果中要更新什么。
通常应该使用内置的Realm过滤机制
let results = realm.objects(ItemClass.self).filter("product != nil")
这些结果将实时更新-如果对象离开了filter参数,结果将紧随其后。如果对象与过滤器匹配,则结果也会更新。
我相信这个Github issue #2138为这个问题提供了更多启示。
如果您绝对需要静态数据,那么我建议您扩展Results类以返回一个数组。像这样
extension Results {
func toArray() -> [Element] {
return compactMap { $0 }
}
}
请记住,这会占用更多内存,因为Realm对象是延迟加载的,而数组不是。
编辑:
该问题中有一些其他信息,因此我制作了一个简单的示例来尝试复制该问题。有一个HouseClass对象,其中包含RoomClass对象的列表,然后扩展HouseClass以返回其列表中所有房间的总宽度。
class RoomClass: Object {
@objc dynamic var room_name = ""
@objc dynamic var width = 0
@objc dynamic var length = 0
@objc dynamic var belongs_to_house: HouseClass!
}
class HouseClass: Object {
@objc dynamic var house_id = NSUUID().uuidString
@objc dynamic var house_name = ""
let rooms = List<RoomClass>()
override static func primaryKey() -> String? {
return "house_id"
}
}
extension HouseClass {
var totalWidth: Int {
let width = Array(rooms).map {$0.width}.reduce(0,+)
return width
}
var anotherTotalWidth: Int {
let width = rooms.map {$0.width}.reduce(0,+)
return width
}
}
然后是代码,它基于两个不同的功能获取所有房屋并输出其房屋宽度(请参见HouseClass扩展)
let houseResults = realm.objects(HouseClass.self)
for house in houseResults {
let w0 = house.totalWidth
print(w0)
let w1 = house.anotherTotalWidth
print(w1)
}
我添加了100套房屋,每套房屋有3个房间,并多次运行以上代码而没有崩溃。