使用Xcode-8.2.1、Swift-3.0.2、RealmSwift-2.2.0、iOS-Simulator-10:
我尝试使用Realm应用MVVM模式(explained by Steve Scott here)。
在我尝试访问一个viewmodel-property之前(在VIEW-part内部,见下文),一切都会正常工作。上面写着:Realm accessed from incorrect thread
我怎样才能让MVVM-pattern在分离模型、视图-模型和视图的同时,获得realm的线程安全呢?
有没有办法让Realm-results (即Results<BalancesDataEntry>)跨线程传递?
下面是我的代码:(问题发生在最底层的View-part内部)
// REALM-OBJECT:
import Foundation
import RealmSwift
class BalancesDataEntry: Object {
dynamic var category: String = ""
dynamic var index: Int = 0
}型号:
import Foundation
import RealmSwift
class MVVMCBalancesModel: BalancesModel
{
fileprivate var entries = [BalancesDataEntry]()
let realm = try! Realm()
init() {
self.createDataEntries()
}
fileprivate func createDataEntries() {
let myBalance = BalancesDataEntry()
myBalance.index = 0
myBalance.category = "Love"
try! self.realm.write {
self.realm.deleteAll()
self.realm.add(myBalance)
}
}
func getEntries(_ completionHandler: @escaping (_ entries: [BalancesDataEntry]) -> Void)
{
// Simulate Aysnchronous data access
DispatchQueue.global().async {
let realmThread = try! Realm()
let returnArray: [BalancesDataEntry] = Array(realmThread.objects(BalancesDataEntry.self))
completionHandler(returnArray)
}
}
}视图-模型:
import Foundation
import RealmSwift
class MVVMCBalancesViewModel: BalancesViewModel
{
weak var viewDelegate: BalancesViewModelViewDelegate?
weak var coordinatorDelegate: BalancesViewModelCoordinatorDelegate?
fileprivate var entries: [BalancesDataEntry]? {
didSet {
viewDelegate?.entriesDidChange(viewModel: self)
}
}
var model: BalancesModel? {
didSet {
entries = nil;
model?.getEntries({ (myEntries) in
self.entries = myEntries
})
}
}
var title: String {
return "My Balances"
}
var numberOfEntries: Int {
if let entries = entries {
return entries.count
}
return 0
}
func entryAtIndex(_ index: Int) -> BalancesDataEntry?
{
if let entries = entries , entries.count > index {
return entries[index]
}
return nil
}
func useEntryAtIndex(_ index: Int)
{
if let entries = entries, let coordinatorDelegate = coordinatorDelegate , index < entries.count {
coordinatorDelegate.balancesViewModelDidSelectData(self, data: entries[index])
}
}
}查看:
import UIKit
class MVVMCBalancesViewController: UIViewController {
@IBOutlet weak var label1Outlet: UILabel!
@IBOutlet weak var label2Outlet: UILabel!
var viewModel: BalancesViewModel? {
willSet {
viewModel?.viewDelegate = nil
}
didSet {
viewModel?.viewDelegate = self
refreshDisplay()
}
}
var isLoaded: Bool = false
func refreshDisplay()
{
if let viewModel = viewModel , isLoaded {
// !!!!!!! HERE IS THE ISSUE: Realm accessed from incorrect thread !!!!
self.label1Outlet.text = viewModel.entryAtIndex(0)?.category
self.label2Outlet.text = viewModel.entryAtIndex(1)?.category
} else {
}
}
override func viewDidLoad()
{
super.viewDidLoad()
isLoaded = true
refreshDisplay();
}
}
extension MVVMCBalancesViewController: BalancesViewModelViewDelegate
{
func entriesDidChange(viewModel: BalancesViewModel)
{
}
}发布于 2017-02-21 04:05:16
您可以使用ThreadSafeReference将Realm的线程受限类型(Object、Results、List、LinkingObjects)传递给不同的线程。文档中关于Passing Instances Across Threads的部分包含了跨线程传递Object子类的单个实例的示例:
let person = Person(name: "Jane")
try! realm.write {
realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "background").async {
let realm = try! Realm()
guard let person = realm.resolve(personRef) else {
return // person was deleted
}
try! realm.write {
person.name = "Jane Doe"
}
}它可以类似地用于Results。
发布于 2017-02-19 00:00:07
我已经找到了一个解决方法(见下文):也许你有更好的解决方案--请让我知道!
这是我的github-code realm_mvvm_c on github
在引入了一个新的协议并使(几乎所有的)符合它之后,事情就解决了。
下面是名为DataEntry的协议:
import Foundation
protocol DataEntry: class {
var idx: Int { get set }
var category: String { get set }
}现在,让所有内容都符合它,比如
--> realm对象(即class BalancesDataEntry: Object, DataEntry {...)
--> getEntries返回值(即func getEntries(_ completionHandler: @escaping (_ entries: [DataEntry]) -> Void))
-->视图-模型的条目(即fileprivate var entries: [DataEntry]? {..)
-->所有相应的模型和视图模型协议也需要DataEntry数据类型(参见git-repo了解完整的图片)
在此之后,将模型的方法getEntries(..)的完成处理程序返回数组更改为新创建的对象实例(即。DataEntryDub)是符合DataEntry协议的:
func getEntries(_ completionHandler: @escaping (_ entries: [DataEntry]) -> Void)
{
// Simulate Aysnchronous data access
DispatchQueue.global().async {
let realmThread = try! Realm()
class DataEntryDub: DataEntry {
var idx: Int
var category: String
init(idx: Int, category: String) {
self.idx = idx
self.category = category
}
}
var returnArray = [DataEntry]()
for entry in realmThread.objects(BalancesDataEntry.self) {
returnArray.append(DataEntryDub(idx: entry.idx, category: entry.category))
}
completionHandler(returnArray)
}
}https://stackoverflow.com/questions/42313354
复制相似问题