从另一个线程通知 UITable

Posted

技术标签:

【中文标题】从另一个线程通知 UITable【英文标题】:Notify UITable from an other Thread 【发布时间】:2017-11-16 10:41:10 【问题描述】:

我有一个简单的 UITable 实现和一个名为 fruits 的数组。取自this 示例。唯一的区别是我将 UIViewController 用于 UITableViewController 的 UITable,但这现在应该无关紧要。

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 

    var fruits : [String] = Array() 
    let thread : GetDataForFruitsArrayThread

    func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return fruits.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)

        cell.textLabel?.text = fruits[indexPath.row]

        return cell
    

    

现在我在这个类中也有一个 viewDidLoad 函数。在函数中,我调用了一个线程,该线程将数组作为参数。线程正在异步地用新值填充数组。意味着我不知道是否会有任何值或值何时出现并设置到数组中。所以你可以想象我想在这一点上问什么:一旦视图将数组加载到 UITable 中,我如何通知 UITableView 我已经更改了数组的内容。在 c# 中有一个 NotifyAll() 函数,它通知所有监听器到一个属性。是否有一种简单且高效的方法可以快速执行此操作,可选择不导入任何未包含的库?

override func viewDidLoad() 
    super.viewDidLoad()
    self.thread = GetDataForFruitsArrayThread(array: &fruits)
    self.thread.StartAsynchronously() 


编辑 - 添加 GetDataForFruitsArrayThread

 class GetDataForFruitsArrayThread : MyThread 

 var array : [String]

 init(array: inout [String] ) 
   self.array = array
 


 override func main() 

      // init socket

 while(true)

      _ = withUnsafeMutablePointer(to: &rcvaddr)
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1)
      recvfrom(m_socket, &pData, bufferlength, 0, UnsafeMutablePointer($0), 
               &socketAddressLength)
            
        

        var fruit = String(cString:inet_ntoa(rcvaddr.sin_addr), encoding: .ascii)
        self.array.append(fruit)

   
 

编辑 - 21.11.2017:

按照 Sandeep Bhandari 的回答,我在 ViewController 中更改了以下代码:

@IBOutlet weak var tableView1: UITableView!

var fruits : [String] = Array() 
        didSet 
            self.tableView1.reloadData()
        
    

问题:我在 GetDataForFruitsArrayThread 类的 array.append(fruit) 处设置断点。之后在 didSet 方法中有一个断点。但是这个断点在 append() 调用之后不会被调用!注意:GetDataForFruitsArrayThread 类的 init 函数上的参数是一个 in-out 参数!

更新:我发现如果我对 GetDataForFruitsArrayThread 线程中的 GetDataForFruitsArrayThread.array 执行 array.append(fruit)-call,ViewController-class 中的 Fruits-array 不会改变,因此 didSet 没有得到叫。我该如何改变这种行为?

【问题讨论】:

在你的方法中添加一个闭包参数,当你的网络函数结束时得到通知的回调 该函数根本没有结束,它是一个无限线程,在应用程序运行时尝试从网络接收数据包。你的意思是我应该传递一个句柄作为参数,每次添加元素时都会调用它?如果是,那么如果触发了处理程序,ViewController 会发生什么? UITable 以某种方式重新加载,这怎么可能? 其相同的方法添加一个闭包并使用您的对象数组作为参数执行此闭包,每次您需要时,当调用此闭包时,您必须更新您的 viewController 对象数组并更新您的 UITableView根据 你有关于这个闭包的一些例子/样本吗?我不完全明白它应该做什么 我认为也许你的viewController 充当你的GetDataForFruitsArrayThread 的代表可以通知你的viewController,你还必须在你的类范围内声明你的线程变量,我不是100%肯定但是可能在 viewDidLoad 结束后被释放,这是另一种方法 【参考方案1】:

因为您说您正在运行一个无休止的过程来不断更新您的数组,并且您希望在数组更改后更新 UI,您可以使用以下解决方案。

var fruits : [String] = Array() 
        didSet 
            self.tableView.reloadData()
        
    

我在做什么? Simple 向数组添加了一个 setter,每当值更改时,我都会重新加载 tableView。

编辑:

仅当您修改传递给GetDataForFruitsArrayThread的inout fruits 数组时,上述解决方案才有效

self.thread = GetDataForFruitsArrayThread(array: &fruits)

所以不要在GetDataForFruitsArrayThread 中再创建一个数组属性,而是直接修改传递给GetDataForFruitsArrayThread 的数组。

【讨论】:

通过编辑,您的意思是不要在 GetDataForFruitsArrayThread 的构造函数中执行此操作: self.array = fruits.对?但是,如果我不将其安全地保存到数组变量中,我如何才能访问 main() 函数中的 fruits 参数? @david :不,这不是我的意思,你正在做的很好:) 我的意思是使用已经传递给你的同一个数组实例,而不是创建一个单独的实例的数组。我希望你知道深浅拷贝。 InOut 参数通过引用传递。所以使用相同的参考。当你半张贴你的问题时,我写了那个编辑。查看名为数组的变量,我认为您可能拥有新的数组实例,而不是使用传递给您的那个:) self.array = fruits 不会创建一个新的数组实例,而是创建一个指向同一个数组的指针,这很好 self.array = [String]() 会创建一个新实例,第二个不会使用建议的解决方案。您现在所做的应该可以正常工作:) @David:如果有帮助,请考虑接受答案:) 首先感谢您的帮助。我会在我的 Xcode 更新后立即尝试(可能需要时间),如果它确实有效(但它听起来是正确的,正是我需要的)我当然会接受并支持你的分析器!目前我只是在理论上问,当我有机会尝试时,我也会发送一些反馈。

以上是关于从另一个线程通知 UITable的主要内容,如果未能解决你的问题,请参考以下文章

Swift:使用完成处理程序从另一个通知 ViewController

从另一个线程访问线程本地

从另一个线程访问 UI 线程的视图

如何从另一个线程取消 GTK3 线程?

信号没有从另一个线程调用槽

从另一个线程更新 oxyplot 模型