vDSP_zrvmul 未返回任何结果(或全为零)
vDSP_zrvmul not returning any results (or all zeros)
根据其他用户的评论,我整理了我的代码并对其进行了压缩以使其可读。我有一个 complexFloatArray class,用于存储复杂向量数组
class complexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
然后我在这个 class 的扩展中定义了一些函数。一个是:
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
这个想法是当在 complexFloatArray 的实例上调用时,它会创建一个 DSPSplitComplex 指针以用于 Accelerate 框架。
最后我有了一个加速函数,我想使用它 (vDSP_zrvmul) 将我的复数向量乘以实数向量。
func floatMultiply(with other: [Float]) -> complexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = complexFloatArray.zeros(count: other.count)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zrvmul(
&selfPointer, complexFloatArray.stride,
other, complexFloatArray.stride,
&resultPointer, complexFloatArray.stride,
vDSP_Length(result.count))
}
}
return result
}
我调用该函数使用:
var kernel = sine.floatMultiply(with: gauss)
其中 sine 是一个 complexFloatArray,gauss 是一个 FloatArray,两者长度相等以创建 morlet 小波。然而,结果是一个用零填充的 complexFloatArray。
调试时,我可以在 floatMultiply 函数中的任意点放置一个断点,并确认 self 和 other(正弦和高斯)都充满了值。所以它在 vDSP 调用中的某处没有返回正确的结果。
为了完整性 complexFloatArray.stride = 1(此值在 complexFloatArray class 中声明)。
和 'zeros' 是 complexFloatArray 中的一个函数,用于用一定长度的零填充数组。 (数组(重复:0, count:N)
有什么建议可以解释为什么我在这次通话中的结果为零吗?
我现在已经包括了完整的代码,而不是给出不完整图片的片段。
ComplexFloatArray Class 的完整代码如下:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
extension ComplexFloatArray {
var count: Int {
assert(reals.count == imaginaries.count)
return reals.count
}
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
}
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
}
extension ComplexFloatArray {
convenience init() {
self.init(reals:[], imaginaries:[])
}
static func zeros(count: Int) -> ComplexFloatArray {
return ComplexFloatArray(reals:Array(repeating: 0, count: count), imaginaries: Array(repeating:0, count:count))
}
}
extension ComplexFloatArray {
enum ComplexMultiplicationType: Int32 { case normal = 1, conjugate = -1}
func ComplexMultiply(
with other: ComplexFloatArray,
multiplicationType: ComplexMultiplicationType = .normal
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: self.count)
self.useAsDSPSplitComplex { selfPointer in
other.useAsDSPSplitComplex { otherPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zvmul(
&selfPointer, ComplexFloatArray.stride,
&otherPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count),
multiplicationType.rawValue)
}
}
}
return result
}
}
extension ComplexFloatArray {
func floatMultiply(
with other: [Float]
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: other.count)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zrvmul(
&selfPointer, ComplexFloatArray.stride,
other, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count))
}
}
return result
}
}
extension ComplexFloatArray {
enum FourierTransformDirection: Int32 { case forward = 1, inverse = -1 }
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize:Int,
logSize: UInt,
direction: FourierTransformDirection) -> ComplexFloatArray {
var result = ComplexFloatArray.zeros(count:resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_fft_zop(
setup,
&selfPointer,
ComplexFloatArray.stride,
&resultPointer,
ComplexFloatArray.stride,
logSize,
direction.rawValue)
}
}
return result
}
}
我的 CWT class 的完整代码如下:
var nVoices = 96 //number of voices per octave
var kernelLength = 2048 //Length of N
var fs = globalSampleRate
class CWT{
var timeArray:[Float] = []
var sines: [ComplexFloatArray] = []
var gaussian:[[Float]] = []
var fftFilterBank:[ComplexFloatArray] = []
var filterBank:[ComplexFloatArray] = []
var convProduct:[ComplexFloatArray] = []
var centreFreqs:[Float]=[]
var phase:[Float] = []
var magnitude:[Float] = []
func synthesizeKernels(){
timeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
centreFreqs = getCentreFreqs(N:timeArray.count)
for i in 0..<centreFreqs.count {
makeSine(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeGaus(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeMorlet(sine: sines[i], gauss: gaussian[i], count:timeArray.count, iteration: i)
fftKernel(kernel: filterBank[i], N:timeArray.count, iteration:i)
}
}
func convolveSignal(realSamples:[Float], imagSamples:[Float]) {
let logN = 11
let fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var product = ComplexFloatArray.zeros(count: filterBank.count)
var input = ComplexFloatArray(reals: realSamples, imaginaries: imagSamples)
var fftOfSamples = ComplexFloatArray.zeros(count: input.count)
fftOfSamples = input.outOfPlaceComplexFourierTransform(setup: fft1Setup, resultSize: input.count, logSize: UInt(logN), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
fftOfSamples.removeAtIndex(index: 0)
for i in 0..<self.filterBank.count {
var kernel = fftFilterBank[i]
var multiplyResult = kernel.ComplexMultiply(with: fftOfSamples)
convProduct.append(multiplyResult)
}
}
//HELPER FUNCTION FOR TIME ARRAY
func makeArray(from:Float, to:Float, increment:Float) ->[Float]{
var Array:[Float]=[]
for i in stride(from: from, to: to, by: increment) {
Array.append(i)
}
return Array
}
//MAKE COMPLEX SINE WAVE
func makeSine(freq:Float, N:Int, iteration:Int) {
var compSine = ComplexFloatArray.init()
for i in 0..<timeArray.count{
let x = 2 * Float.pi * freq * timeArray[i]
compSine.append(real: cos(x), imaginary: sin(x))
}
sines.append(compSine)
}
//MAKE GAUSSIAN WINDOW
func makeGaus(freq:Float, N:Int, iteration:Int) {
var gaus:[Float] = Array(repeating:0, count:N)
let s:Float = 7 / (2.0 * Float.pi * freq)
let interimCalc: Float = Float(2)*Float(pow(s,2))
for i in 0..<N{
var u = pow(timeArray[i],2)
u = (-u)
let v = u / interimCalc
gaus[i] = exp(v)
}
gaussian.append(gaus)
}
//CREATE CENTRE FREQUENCIES
func getCentreFreqs(N:Int) ->[Float]{
var CF:[Float] = []
var filteredCF:[Float] = []
var G:Float = pow(10,(3/10))
var x = makeArray(from: -1000, to: 1350, increment: 1)
for i in 0..<x.count {
var fraction:Float = (Float(2*Float(x[i]))-Float(59.0)) / Float(2*nVoices)
var fr:Float = Float(1000.0) * Float(powf(Float(G), Float(fraction)))
CF.append(fr)
}
for i in 0..<CF.count {
if (Float(20) < CF[i] && CF[i] < Float(20000)) {
filteredCF.append(CF[i])
}
}
return filteredCF
}
//MAKE COMPLEX MORLET WAVELET
func makeMorlet(sine:ComplexFloatArray, gauss:[Float], count:Int, iteration:Int) {
var kernel = sine.floatMultiply(with: gauss)
filterBank.append(kernel)
}
//PERFORM FFT ON KERNEL
func fftKernel(kernel: ComplexFloatArray, N:Int, iteration:Int) {
var size = kernel.count
var logSize = 11
var FFTSetup = vDSP_create_fftsetup(vDSP_Length(logSize), FFTRadix(FFT_RADIX2))
var output = kernel.outOfPlaceComplexFourierTransform(setup: FFTSetup!, resultSize: size, logSize: UInt(logSize), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
output.removeAtIndex(index:0)
fftFilterBank.append(output)
}
//Test Signal to Convolve - 1kHz Sine Wave
func testSine(){
var testTimeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
var testSine = ComplexFloatArray.zeros(count: testTimeArray.count)
for i in 0..<testTimeArray.count{
var x = 2 * Float.pi * 1000 * testTimeArray[i]
testSine.reals[i] = cos(x)
testSine.imaginaries[i] = sin(x)
}
convolveSignal(realSamples: testSine.reals, imagSamples:testSine.imaginaries)
}
}
最后在我的 ViewController class 我有以下内容:
class ViewController: UIViewController {
var wavelet = CWT()
func viewDidLoad(){
wavelet.synthesizeKernels()
wavelet.testSine()
}
}
如果我调试它并在 makeMorlet 函数上暂停,FloatMultiply 的结果全为零,尽管等式左右两边的长度值相同。
不幸的是,您的代码无法在 Xcode 10.2 上 运行 使用默认设置。
Thread 1: Simultaneous accesses to 0x600001170550, but modification requires exclusive access
我不确定您是将 独占访问内存 设置为关闭(仅编译时强制执行),还是使用某些旧版本的 Xcode,但是 Swift 假设排他性执行完全有效,编译器会优化并生成代码。 (因此,永远不要关闭对内存的独占访问。)
请仔细阅读本文:
Swift 5 Exclusivity Enforcement
您在 ComplexFloatArray
中对 count
的实施违反了这一规定。在执行传递给 reals.withUnsafeMutableBufferPointer
的闭包时,您无法访问 reals
,因为数组已被该方法独占。
如果违反此规则,Swift 运行时间可能会出现任何意外行为。
尝试像下面这样更改 count
的实现,看看会发生什么:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
assert(reals.count == imaginaries.count)
self.count = reals.count
}
//Make `count` a stored property.
var count: Int
}
extension ComplexFloatArray {
//Remove this computed property.
// var count: Int {
// assert(reals.count == imaginaries.count)
// return reals.count
// }
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
count += 1
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
count -= 1
}
//...
}
另外,您的代码会生成许多带有推荐设置的警告,您最好不要忽略它们。
根据其他用户的评论,我整理了我的代码并对其进行了压缩以使其可读。我有一个 complexFloatArray class,用于存储复杂向量数组
class complexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
然后我在这个 class 的扩展中定义了一些函数。一个是:
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
这个想法是当在 complexFloatArray 的实例上调用时,它会创建一个 DSPSplitComplex 指针以用于 Accelerate 框架。
最后我有了一个加速函数,我想使用它 (vDSP_zrvmul) 将我的复数向量乘以实数向量。
func floatMultiply(with other: [Float]) -> complexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = complexFloatArray.zeros(count: other.count)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zrvmul(
&selfPointer, complexFloatArray.stride,
other, complexFloatArray.stride,
&resultPointer, complexFloatArray.stride,
vDSP_Length(result.count))
}
}
return result
}
我调用该函数使用:
var kernel = sine.floatMultiply(with: gauss)
其中 sine 是一个 complexFloatArray,gauss 是一个 FloatArray,两者长度相等以创建 morlet 小波。然而,结果是一个用零填充的 complexFloatArray。
调试时,我可以在 floatMultiply 函数中的任意点放置一个断点,并确认 self 和 other(正弦和高斯)都充满了值。所以它在 vDSP 调用中的某处没有返回正确的结果。
为了完整性 complexFloatArray.stride = 1(此值在 complexFloatArray class 中声明)。
和 'zeros' 是 complexFloatArray 中的一个函数,用于用一定长度的零填充数组。 (数组(重复:0, count:N)
有什么建议可以解释为什么我在这次通话中的结果为零吗?
我现在已经包括了完整的代码,而不是给出不完整图片的片段。
ComplexFloatArray Class 的完整代码如下:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
extension ComplexFloatArray {
var count: Int {
assert(reals.count == imaginaries.count)
return reals.count
}
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
}
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
}
extension ComplexFloatArray {
convenience init() {
self.init(reals:[], imaginaries:[])
}
static func zeros(count: Int) -> ComplexFloatArray {
return ComplexFloatArray(reals:Array(repeating: 0, count: count), imaginaries: Array(repeating:0, count:count))
}
}
extension ComplexFloatArray {
enum ComplexMultiplicationType: Int32 { case normal = 1, conjugate = -1}
func ComplexMultiply(
with other: ComplexFloatArray,
multiplicationType: ComplexMultiplicationType = .normal
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: self.count)
self.useAsDSPSplitComplex { selfPointer in
other.useAsDSPSplitComplex { otherPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zvmul(
&selfPointer, ComplexFloatArray.stride,
&otherPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count),
multiplicationType.rawValue)
}
}
}
return result
}
}
extension ComplexFloatArray {
func floatMultiply(
with other: [Float]
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: other.count)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zrvmul(
&selfPointer, ComplexFloatArray.stride,
other, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count))
}
}
return result
}
}
extension ComplexFloatArray {
enum FourierTransformDirection: Int32 { case forward = 1, inverse = -1 }
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize:Int,
logSize: UInt,
direction: FourierTransformDirection) -> ComplexFloatArray {
var result = ComplexFloatArray.zeros(count:resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_fft_zop(
setup,
&selfPointer,
ComplexFloatArray.stride,
&resultPointer,
ComplexFloatArray.stride,
logSize,
direction.rawValue)
}
}
return result
}
}
我的 CWT class 的完整代码如下:
var nVoices = 96 //number of voices per octave
var kernelLength = 2048 //Length of N
var fs = globalSampleRate
class CWT{
var timeArray:[Float] = []
var sines: [ComplexFloatArray] = []
var gaussian:[[Float]] = []
var fftFilterBank:[ComplexFloatArray] = []
var filterBank:[ComplexFloatArray] = []
var convProduct:[ComplexFloatArray] = []
var centreFreqs:[Float]=[]
var phase:[Float] = []
var magnitude:[Float] = []
func synthesizeKernels(){
timeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
centreFreqs = getCentreFreqs(N:timeArray.count)
for i in 0..<centreFreqs.count {
makeSine(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeGaus(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeMorlet(sine: sines[i], gauss: gaussian[i], count:timeArray.count, iteration: i)
fftKernel(kernel: filterBank[i], N:timeArray.count, iteration:i)
}
}
func convolveSignal(realSamples:[Float], imagSamples:[Float]) {
let logN = 11
let fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var product = ComplexFloatArray.zeros(count: filterBank.count)
var input = ComplexFloatArray(reals: realSamples, imaginaries: imagSamples)
var fftOfSamples = ComplexFloatArray.zeros(count: input.count)
fftOfSamples = input.outOfPlaceComplexFourierTransform(setup: fft1Setup, resultSize: input.count, logSize: UInt(logN), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
fftOfSamples.removeAtIndex(index: 0)
for i in 0..<self.filterBank.count {
var kernel = fftFilterBank[i]
var multiplyResult = kernel.ComplexMultiply(with: fftOfSamples)
convProduct.append(multiplyResult)
}
}
//HELPER FUNCTION FOR TIME ARRAY
func makeArray(from:Float, to:Float, increment:Float) ->[Float]{
var Array:[Float]=[]
for i in stride(from: from, to: to, by: increment) {
Array.append(i)
}
return Array
}
//MAKE COMPLEX SINE WAVE
func makeSine(freq:Float, N:Int, iteration:Int) {
var compSine = ComplexFloatArray.init()
for i in 0..<timeArray.count{
let x = 2 * Float.pi * freq * timeArray[i]
compSine.append(real: cos(x), imaginary: sin(x))
}
sines.append(compSine)
}
//MAKE GAUSSIAN WINDOW
func makeGaus(freq:Float, N:Int, iteration:Int) {
var gaus:[Float] = Array(repeating:0, count:N)
let s:Float = 7 / (2.0 * Float.pi * freq)
let interimCalc: Float = Float(2)*Float(pow(s,2))
for i in 0..<N{
var u = pow(timeArray[i],2)
u = (-u)
let v = u / interimCalc
gaus[i] = exp(v)
}
gaussian.append(gaus)
}
//CREATE CENTRE FREQUENCIES
func getCentreFreqs(N:Int) ->[Float]{
var CF:[Float] = []
var filteredCF:[Float] = []
var G:Float = pow(10,(3/10))
var x = makeArray(from: -1000, to: 1350, increment: 1)
for i in 0..<x.count {
var fraction:Float = (Float(2*Float(x[i]))-Float(59.0)) / Float(2*nVoices)
var fr:Float = Float(1000.0) * Float(powf(Float(G), Float(fraction)))
CF.append(fr)
}
for i in 0..<CF.count {
if (Float(20) < CF[i] && CF[i] < Float(20000)) {
filteredCF.append(CF[i])
}
}
return filteredCF
}
//MAKE COMPLEX MORLET WAVELET
func makeMorlet(sine:ComplexFloatArray, gauss:[Float], count:Int, iteration:Int) {
var kernel = sine.floatMultiply(with: gauss)
filterBank.append(kernel)
}
//PERFORM FFT ON KERNEL
func fftKernel(kernel: ComplexFloatArray, N:Int, iteration:Int) {
var size = kernel.count
var logSize = 11
var FFTSetup = vDSP_create_fftsetup(vDSP_Length(logSize), FFTRadix(FFT_RADIX2))
var output = kernel.outOfPlaceComplexFourierTransform(setup: FFTSetup!, resultSize: size, logSize: UInt(logSize), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
output.removeAtIndex(index:0)
fftFilterBank.append(output)
}
//Test Signal to Convolve - 1kHz Sine Wave
func testSine(){
var testTimeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
var testSine = ComplexFloatArray.zeros(count: testTimeArray.count)
for i in 0..<testTimeArray.count{
var x = 2 * Float.pi * 1000 * testTimeArray[i]
testSine.reals[i] = cos(x)
testSine.imaginaries[i] = sin(x)
}
convolveSignal(realSamples: testSine.reals, imagSamples:testSine.imaginaries)
}
}
最后在我的 ViewController class 我有以下内容:
class ViewController: UIViewController {
var wavelet = CWT()
func viewDidLoad(){
wavelet.synthesizeKernels()
wavelet.testSine()
}
}
如果我调试它并在 makeMorlet 函数上暂停,FloatMultiply 的结果全为零,尽管等式左右两边的长度值相同。
不幸的是,您的代码无法在 Xcode 10.2 上 运行 使用默认设置。
Thread 1: Simultaneous accesses to 0x600001170550, but modification requires exclusive access
我不确定您是将 独占访问内存 设置为关闭(仅编译时强制执行),还是使用某些旧版本的 Xcode,但是 Swift 假设排他性执行完全有效,编译器会优化并生成代码。 (因此,永远不要关闭对内存的独占访问。)
请仔细阅读本文:
Swift 5 Exclusivity Enforcement
您在 ComplexFloatArray
中对 count
的实施违反了这一规定。在执行传递给 reals.withUnsafeMutableBufferPointer
的闭包时,您无法访问 reals
,因为数组已被该方法独占。
如果违反此规则,Swift 运行时间可能会出现任何意外行为。
尝试像下面这样更改 count
的实现,看看会发生什么:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
assert(reals.count == imaginaries.count)
self.count = reals.count
}
//Make `count` a stored property.
var count: Int
}
extension ComplexFloatArray {
//Remove this computed property.
// var count: Int {
// assert(reals.count == imaginaries.count)
// return reals.count
// }
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
count += 1
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
count -= 1
}
//...
}
另外,您的代码会生成许多带有推荐设置的警告,您最好不要忽略它们。