简体   繁体   中英

Swift EXC_BAD_ACCESS when unwrapping optional weak property of protocol type

I have this code in my Xcode playground that gives me EXC_BAD_ACCESS error on last line:

protocol SomeProtocol: class {
    func test()
}

class SomeClass: SomeProtocol {
    func test(){}
}

struct Weak<T: AnyObject> {
    weak var value: T?

    init(_ value: T) {
        self.value = value
    }
}

var value: SomeProtocol = SomeClass()
var w = Weak(value)

w.value?.test()  // EXC_BAD_ACCESS

If I add @objc to protocol definition than code executes without any errors:

import Foundation

@objc protocol SomeProtocol: class {
    func test()
}

class SomeClass: SomeProtocol {
    @objc func test(){}
}

struct Weak<T: AnyObject> {
    weak var value: T?

    init(_ value: T) {
        self.value = value
    }
}

var value: SomeProtocol = SomeClass()
var w = Weak(value)

w.value?.test()

I suspect that these lines of Apple documentation somehow relate to my case:

Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance.

But I do not understand why it does not work without @objc . Could someone explain?

Swift currently does not handle using non-class types with generics well.

The actual location of the EXC_BAD_ACCESS is when the result of Weak(value) is assigned to var w . You can see this by adding the println statements around the var w = Weak(value) .

To get around these problems with Swift you'll need to Box values with non-class types to use them with generics.

Hopefully in the next few versions of Swift Apple will fix these issues and we'll no longer need to box values.

final class Box<T> {
    private var value: T

    init(_ value: T) {
        self.value = value
    }

    var unbox: T {
        return value
    }
}

protocol SomeProtocol : AnyObject {
    func test()
}

class SomeClass: SomeProtocol {
    func test(){
        println("Test")
    }
}

struct Weak<T: AnyObject> {
    weak var value: T?

    init(_ value: T) {
        println("Weak Init Start")
        self.value = value
        println("Weak Init Stop")
    }
}

var value: SomeProtocol = SomeClass()

//Method in Question

println("Before Weak Init")
// var w = Weak(value) // EXC_BAD_ACCESS
println("After Weak Init")

//w.value?.test()


// Method with Box

var box = Box(value)
var w = Weak(box)

w.value?.unbox.test() // prints "Test"

w = Weak(Box(value))
w.value?.unbox.test() // nil, since nothing retains the Box(value) result

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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