首页 > 解决方案 > 调用函数后释放类变量

问题描述

我在swift中有一个功能,如下所示。有一个引用存在于此类实例中的变量的循环。(fftfilterbankReal 是类中的一个数组)。但是,经过一次后,我在代码行“for i in 0..”处出现“索引超出范围”的错误。

在调试器中,似乎在此循环的第二次迭代中,“self”下拉列表下没有变量。

如果我注释掉 'vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)' 行,则循环运行,我可以随时调试并直观地看到 self 变量调试器。

我错过了什么似乎使这些变量消失了?我已经阅读了内存分配等内容,并且我的类变量是使用 'var' 声明的,仅此而已,因为这在 swift 中应该默认为强。

func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
    realResult = Array(repeating: [], count: filterbankReal.count)
    imagResult = Array(repeating: [], count: filterbankReal.count)
    let x = realsamples
    let y = imagsamples
    var N = x.count
    var logN = 16          
    var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!

    var paddedLength = x.count + filterbankReal.count - 1
    var halfPaddedLength = paddedLength/2
    var halfKernelLength = kernelLength/2
    //setup Complex Buffer 1
    var reals = [Float]()
    var imags = [Float]()
    for i in 0..<x.count{
        reals.append(x[i])
        imags.append(y[i])

    }
    var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))

    //Perform FFT on incoming samples
    var re = [Float](repeating:0.0, count: N)
    var im = [Float](repeating:0.0, count: N)
    var fft1Input = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: re), imagp: UnsafeMutablePointer(mutating: im))

    var fftlength = 10
    vDSP_fft_zop(fft1Setup, &(complexBuffer1), 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))

    //Remove DC from FFT Signal
    re.remove(at: 0)
    im.remove(at: 0)

for i in 0..<self.fftfilterbankReal.count {
 var r:[Float] = self.fftfilterbankReal[i]           
        var im:[Float] = self.fftfilterbankImag[i]          
        var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)
var res:Float = 0
        var ims:Float = 0
        var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
        vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)
        self.realResult[i].append(res)
        self.imagResult[i].append(ims)
    }

标签: swiftloopsvariablesmemory

解决方案


在使用数组和指针时,您的代码是一种不良用法的展示。

例如:

var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))

或者:

var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)

DSPSplitComplex分别持有实部和虚部的两个指针,不复制内容。您不应该为此类参数传递 Swift 数组。

你的代码中最关键的部分是......

var res:Float = 0
var ims:Float = 0
var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)

vDSP_zvmul生成N(在您的代码中N= vDSP_Length(r.count))复数,因此您需要准备一个可以容纳N元素的区域。

使用当前代码调用vDSP_zvmul后,您会破坏整个堆栈内容,这会导致您所经历的:

在调试器中,似乎在此循环的第二次迭代中,“self”下拉列表下没有变量。


您隐藏了代码的许多部分,因此很难猜测您真正想要做什么,但是如果我以更安全的方式重新编写您的代码,它将是这样的:

func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
    realResult = Array(repeating: [], count: filterbankReal.count)
    imagResult = Array(repeating: [], count: filterbankReal.count)
    let x = realsamples
    let y = imagsamples
    var N = x.count
    var logN = 16
    var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!

    var paddedLength = x.count + filterbankReal.count - 1
    var halfPaddedLength = paddedLength/2
    var halfKernelLength = kernelLength/2
    //setup Complex Buffer 1
    var reals = UnsafeMutableBufferPointer<Float>.allocate(capacity: x.count)
    defer {reals.deallocate()}
    var imags = UnsafeMutableBufferPointer<Float>.allocate(capacity: y.count)
    defer {imags.deallocate()}
    _ = reals.initialize(from: x)
    _ = imags.initialize(from: y)
    var complexBuffer1 = DSPSplitComplex(realp: reals.baseAddress!, imagp: imags.baseAddress!)

    //Perform FFT on incoming samples
    var re = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
    defer {re.deallocate()}
    var im = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
    defer {im.deallocate()}
    var fft1Input = DSPSplitComplex(realp: re.baseAddress!, imagp: im.baseAddress!)

    let fftlength = 10
    vDSP_fft_zop(fft1Setup, &complexBuffer1, 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))

    //Remove DC from FFT Signal
    fft1Input = DSPSplitComplex(realp: re.baseAddress!+1, imagp: im.baseAddress!+1)

    for i in 0..<self.fftfilterbankReal.count {
        self.fftfilterbankReal[i].withUnsafeMutableBufferPointer {rBuf in
            self.fftfilterbankImag[i].withUnsafeMutableBufferPointer {imBuf in
                var kernel = DSPSplitComplex(realp: rBuf.baseAddress!, imagp: imBuf.baseAddress!)
                var res = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
                defer {res.deallocate()}
                var ims = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
                defer {ims.deallocate()}
                var result:DSPSplitComplex = DSPSplitComplex(realp: res.baseAddress!, imagp: ims.baseAddress!)
                vDSP_zvmul(&kernel, 1, &fft1Input, 1, &result, 1, vDSP_Length(rBuf.count), 1)
                //vDSP_zvmul generates `N` complex numbers,
                // I do not understand what you really want to do...
                self.realResult[i].append(res[0])
                self.imagResult[i].append(ims[0])
            }
        }
    }

    //...
}

可能还有其他部分需要修复,但无论如何,请尝试看看你得到了什么。


推荐阅读