繁体   English   中英

在Swift中完成CloudKit异步操作时设置UILabel文本

[英]Set UILabel Text at Completion of CloudKit Asyncronous Operation in Swift

我是Swift和异步代码的新手,所以告诉我这是否可行。 基本上我想:

  1. 开启应用程式
  2. 触发读取CloudKit记录
  3. 读取完成后,UILabel将显示检索到的记录数

这本身显然没有用,但是作为一个原则,它将帮助我理解异步代码操作以及如何在完成操作时触发操作。

// 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类中使用didSet设置文本来实现var,将var设置为privateDB.perform代码中所需的值以触发更改

这些都产生与上述相同的问题。

是的,我知道.perform中没有任何错误处理,是的,有记录。 如果在加载视图几秒钟后手动将UILabel文本的设置触发为记录计数,则可以正常工作。

因此,问题是...如何使用数据库的完成读取作为触发器将记录的属性加载到视图?

谢谢

问题出在这一行: let VC=ViewController() 在这里,您实例化了ViewController类的新实例,并尝试在该新创建的实例上设置标签。 但是,您需要在当前显示的viewController实例上设置标签。

只需将此行VC.myLabel.text = ("\\(allRecs?.count) records retreived") self.myLabel.text = ("\\(allRecs?.count) records retreived") VC.myLabel.text = ("\\(allRecs?.count) records retreived")更改为self.myLabel.text = ("\\(allRecs?.count) records retreived") ,它应该可以正常工作。

知道了,解决方案如下所示:

// 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类型别名来加载数据库记录,这将返回记录数和一个可选错误。

现在,完成操作可以存在于ViewController类中,并可以使用self.myLabel访问UILabel,它可以解决较早发生的错误,同时使数据库加载代码与ViewController类分开。

此版本的代码还具有基本的错误处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM