Ios 在Swift中完成CloudKit异步操作时设置UILabel文本
我对Swift和异步代码都是新手,所以请告诉我这是否太离谱了。基本上我想:Ios 在Swift中完成CloudKit异步操作时设置UILabel文本,ios,swift,swift3,Ios,Swift,Swift3,我对Swift和异步代码都是新手,所以请告诉我这是否太离谱了。基本上我想: 打开应用程序 这会触发对CloudKit记录的读取 读取完成后,UILabel将显示检索到的记录数 这本身显然没有什么用处,但作为一项原则,它将帮助我理解异步代码操作,以及如何在操作完成时触发操作 // In ViewController Swift file: class ViewController: UIViewController{ override func viewDidLoad() {
// In ViewController Swift file:
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
readDatabase()
}
@IBOutlet weak var myLabel: UILabel!
}
let VC=ViewController()
//In Another Swift file:
func readDatabase() {
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "myRecord", predicate: predicate)
let container = CKContainer.default()
let privateDB = container.privateCloudDatabase
privateDB.perform(query, inZoneWith:nil) { (allRecs, err) in
VC.myLabel.text = ("\(allRecs?.count) records retreived")
/*
ERROR OCCURS IN LINE ABOVE:
CONSOLE: fatal error: unexpectedly found nil while unwrapping an Optional value
BY CODE LINE: Thread 8:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
*/
}
}
我可以从viewDidLoad函数中设置文本字段,那么为什么不从该函数中调用的函数中设置呢
我还尝试了其他一些方法:
- 使用异步调度将其放在线程1上
- 在ViewController类中使用实现var,使用设置文本的didSet,将var设置为privateDB中的所需值。执行代码以触发更改
谢谢这一行有问题:
让VC=ViewController()
。在这里,您将实例化ViewController类的一个新实例,并尝试在新创建的实例上设置标签。但是,您可能希望在当前显示的viewController实例上设置标签
只要将这一行
VC.myLabel.text=(“\(allRecs?.count)records retreved”)
更改为self.myLabel.text=(“\(allRecs?.count)records retreved”)
就可以了。明白了,解决方案如下:
// In ViewController Swift file:
typealias CompletionHandler = (_ recCount:Int,_ err:Error?) -> Void
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
readDatabase(completionHandler: { (recCount,success) -> Void in
if err == nil {
self.myLabel.text = "\(recCount) records loaded"
} else {
self.myLabel.text = "load failed: \(err)"
}
})
}
@IBOutlet weak var myLabel: UILabel!
}
//In Another Swift file:
func readDatabase() {
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "myRecord", predicate: predicate)
let container = CKContainer.default()
let privateDB = container.privateCloudDatabase
privateDB.perform(query, inZoneWith:nil) { (allRecs, err) in
if let recCount = allRecs?.count {
completionHandler(recCount,err)
} else {
completionHandler(0,err)
}
}
}
这与原始的区别在于,它在函数调用中使用CompletionHandler typealias来加载数据库记录,这将返回记录计数和可选错误
完成操作现在可以存在于ViewController类中,并使用self.myLabel访问UILabel,这解决了之前发生的错误,同时将数据库加载代码与ViewController类分开
此版本的代码还具有基本的错误处理。您还可能(不确定,因为我从未使用过此框架)更新主线程中的标签(闭包位于后台线程中并不奇怪)。将其更改为self.mylabel会导致“使用未解析标识符”self”错误。这是因为readDatabase()函数不在viewController范围内吗?是的,这就是原因,我没有看到关于它在单独类中的注释,抱歉