我正在努力在 swift 项目中展示 React-native-View。我通过异步操作下载bundlde文件,将bundle文件保存在app目录中,并使用它来创建RCTROOTVIEW。我当前的问题是,当我尝试显示视图时,我看到一个空白屏幕,因为下载和保存文件的过程是异步的。我该如何解决这个问题?
我的来源
import UIKit
import React
import SwiftUI
import Foundation
struct ReactNativeView: UIViewRepresentable {
let mockData: NSDictionary = ["scores": [["name": "Alex", "value": "42"], ["name": "Joel", "value": "10"]]]
let jsCodeLocation = URL(string: "https://CDN.com/main.jsbundle")!
func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
func downloadBundle(url: URL, completion: @escaping (URL?, Error?) -> Void) {
let documentsUrl = getDocumentsDirectory()
let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
URLSession.shared.downloadTask(with: url) { (tempLocalUrl, response, error) in
guard let tempLocalUrl = tempLocalUrl, error == nil else {
print("Error downloading bundle: \(String(describing: error))")
completion(nil, error)
return
}
do {
try FileManager.default.moveItem(at: tempLocalUrl, to: destinationUrl)
print("File moved to destination [\(destinationUrl.path)]")
completion(destinationUrl, nil)
} catch {
print("Error moving file to destination: \(error)")
completion(nil, error)
}
}.resume()
}
func makeUIView(context: Context) -> UIView {
var rootView : RCTRootView?
downloadBundle(url: jsCodeLocation) { _url, error in
guard let localURL = _url, error == nil else {
print("error saving file")
return
}
rootView = RCTRootView(
bundleURL: localURL,
moduleName: "RNHighScores",
initialProperties: mockData as [NSObject: AnyObject],
launchOptions: nil
)
}
return rootView ?? UIView()
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
使用代码
@objc private func showReactNativeView() {
let reactNativeViewController = UIHostingController(rootView: ReactNativeView())
present(reactNativeViewController, animated: true, completion: nil)
}
...
containerButton.rx.tap
.asDriverOnErrorJustComplete()
.drive(onNext: { [weak self] in
self?.showReactNativeView()
})
.disposed(by: disposeBag)
最后,如果您已经下载了文件,我想删除或覆盖它。
func makeUIView(context: Context) -> UIView
返回 nil。这从根本上来说是不好的,因为您永远不应该在同步上下文中的异步操作中分配返回的变量来返回结果。有很多方法可以解决这个问题:
RCTRootView
内部执行异步操作,这样它就可以自我更新,而不需要SwiftUI做任何事情
func makeUIView(context: Context) -> UIView
中的一个容器视图,然后操作完成后,创建
RCTRootView
并将其添加到容器视图中
@State
属性来跟踪进度(加载/完成)并使用该 State 属性更新
func updateUIView(_ uiView: UIView, context: Context)
中的视图。