问题描述
我有这几个环境对象的场景:
func scene(_ scene: UIScene,willConnectTo session: UIScenesession,options connectionoptions: UIScene.Connectionoptions) {
// Get the managed object context from the shared persistent container.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// Create the SwiftUI view and set the context as the value for the managedobjectContext environment keyPath.
// Add `@Environment(\.managedobjectContext)` in the views that will need the context.
let contentView = MainTabView()
//Inject Database repository
.environmentObject(DatabaseRepository())
.environmentObject(UserRepository())
.environmentObject(StockRepository(api: AlphaVantageAPI()))
.environment(\.managedobjectContext,context)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
在我的 MainTabView 中,我创建了一个这样的选项卡:
struct MainTabView: View {
@EnvironmentObject var database: DatabaseRepository
@EnvironmentObject var userRepository: UserRepository
@EnvironmentObject var stockRepository: StockRepository
var viewmodel = MainTabviewmodel()
init() {
UITabBar.appearance().barTintColor = UIColor(named: "primary")
}
var body: some View {
TabView {
HomeView(viewmodel: Homeviewmodel(databaseRepository: database,userRepository: userRepository,stockRepository: stockRepository))
.tabItem {
Image("account_balance_wallet")
.renderingMode(.template)
Text("Home")
}.tag(0)
...
}.accentColor(.white)
}
}
class Homeviewmodel: ObservableObject {
@Published var watchingVMs = [EquityPreviewCellviewmodel]()
private let databaseRepository: DatabaseRepositoryProtocol
private let userRepository: UserRepositoryProtocol
private let stockRepository: StockRepositoryProtocol
init(databaseRepository: DatabaseRepositoryProtocol,userRepository: UserRepositoryProtocol,stockRepository: StockRepositoryProtocol) {
self.databaseRepository = databaseRepository
self.userRepository = userRepository
self.stockRepository = stockRepository
self.bind()
}
func bind() {
let allorders = databaseRepository
.allOrder(userID: userRepository.userID).share()
allorders
.assertNoFailure()
.compactMap({orders in
return orders?.reduce([Order](),{ finalOrders,nextOrder in
var orders = [Order](finalOrders)
if !finalOrders.contains(where: { $0.symbol == nextOrder.symbol }) {
orders.append(nextOrder)
}
return orders
}).map({EquityPreviewCellviewmodel(order: $0,stockRepository: self.stockRepository,userRepository: self.userRepository,dataBaseRepository: self.databaseRepository)})
})
.receive(on: dispatchQueue.main)
.assign(to: &self.$watchingVMs)
我的我启动我的应用程序我有这个崩溃:
线程 1:EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)
我认为我不能很好地使用 environmentObject
,但我不明白为什么。
解决方法
可能是你想要的
.assign(to: \.watchingVMs,on: self)
或(使用弱自我)
.sink { [weak self] value in
self?.watchingVMs = value
}
更新:将本地 allorders
移动到属性以保持引用有效
func bind() {
let allorders = databaseRepository
.allOrder(userID: userRepository.userID).share()
allorders // << this one is destroyed on quit from bind
,
我认为您可能需要将此添加到 MainTabView
:
@Environment(\.managedObjectContext) var managedObjectContext
由于我们使用环境修饰符进行设置,因此您可能会在简单的 @FetchRequest
之上执行保存、删除和其他一些任务。
@Asperi 建议的更改也是完全正确的,应该为此问题添加。这是因为方法签名不同:
.assign(to: \.watchingVMs,on: self)
也可能存在导致 EXC_BAD_ACCESS
的线程问题,这里可能值得检查同步问题,即在同一个主队列上执行提取请求。