【问题标题】:Access class properties from within installTapOnBus closure从 installTapOnBus 闭包中访问类属性
【发布时间】:2016-01-19 19:10:47
【问题描述】:

我有一个非常简单的installTapOnBus 闭包,可以成功更新控制台,但不能更新 UI 元素。代码如下:

self.meter.text="..."
let inputNode = audioEngine.inputNode
let bus = 0

inputNode!.installTapOnBus(bus, bufferSize: 2048, format: inputNode!.inputFormatForBus(bus)) {
    (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
        var someFeature:Float=0.0
        for var i=0; i<Int(buffer.frameLength); i += 1{
           someFeature += fabs(buffer.floatChannelData.memory[i])
        }
        someFeature /= Float(buffer.frameLength)
        self.meter.text="\(someFeature)" // No effect!
        print("\(someFeature)") // This works
    }

也许我需要向闭包发送对self 的弱引用,但我不确定语法。任何关于如何更新 UI 元素的反馈/想法都会很棒!感谢阅读。

【问题讨论】:

    标签: ios swift core-audio avaudioengine


    【解决方案1】:

    您应该只从主线程调用 UIKit。

    来自 UIView 的documentation:

    线程注意事项

    对应用程序用户界面的操作必须在主线程上进行。因此,您应该始终从应用程序主线程中运行的代码调用 UIView 类的方法。唯一可能不是绝对必要的情况是创建视图对象本身但所有其他操作都应在主线程上进行。

    如果您查看AVAudioNode 尤其是installTapOnBus 的API 参考:

    可以在主线程以外的线程上调用 tapBlock。

    您的 UI 没有更新,因为来自 inputNode!.installTapOnBus() 的回调正在后台线程上执行,然后您尝试从该线程更新 UI。

    正如您所发现的,您将希望通过以下方式从主线程进行 UI 调用:

    dispatch_async(dispatch_get_main_queue(), ^{
       /* Make UIKit calls here */
    });
    

    【讨论】:

      【解决方案2】:

      解决方案似乎是在主线程上调用self.meter.text = ...:

      dispatch_async(dispatch_get_main_queue()) { 
          self.meter.text="\(someFeature)"
      }
      

      我会在一两天内不勾选这个答案,以防有人可以填写更多详细信息。

      【讨论】:

        猜你喜欢
        • 2016-11-30
        • 1970-01-01
        • 1970-01-01
        • 2014-08-09
        • 2011-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-24
        相关资源
        最近更新 更多