内存管理 - 尝试在初始化中启用弱内存时"Variable used within its own initial value"



我正在使用包含块的初始值设定项创建我的NSOperation子类:

let concurrentOperation = ABOConcurrentOperation {[weak weakOp = concurrentOperation] in
    ...
}

不幸的是,这不起作用,因为我总是收到对我来说有意义的错误消息Variable used within its own initial value,但是......如何实现并发操作作为内部弱参考?

如果您需要对块中操作的引用,则应将其作为参数传递给闭包,然后就不需要weak引用。闭包完成后,它将自动解析引用。例如,请考虑以下事项:

let queue = NSOperationQueue()
let concurrentOperation = ABOConcurrentOperation() { operation in
    print("(NSDate()): starting operation")
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * Int64(NSEC_PER_SEC)), dispatch_get_main_queue()) {
        print("(NSDate()): finishing operation")
        operation.completeOperation()
    }
}
queue.addOperation(concurrentOperation)

而且,我将闭包定义为标准闭包:

private var block: ((AsynchronousOperation) -> ())?    // FYI, I use optional in case the caller accidentally introduces a strong reference cycle, I can resolve that when the operation completes.

如果你的子类打印了deinit的东西:

/// a subclass that will just confirm that `deinit` is called
class ABOConcurrentOperation: AsynchronousBlockOperation {
    deinit {
        print("deinit")
    }
}

你会看到这就是发生的事情:

2016-07-07 21:20:54 +0000:开始运行
2016-07-07 21:21:01 +0000:完成操作
代尼特

供您参考,这是上面使用的示例AsynchronousOperation类:

/// Asynchronous Operation base class
///
/// This class performs all of the necessary KVN of `isFinished` and
/// `isExecuting` for a concurrent `NSOperation` subclass. So, to developer
/// a concurrent NSOperation subclass, you instead subclass this class which:
///
/// - must override `main()` with the tasks that initiate the asynchronous task;
///
/// - must call `completeOperation()` function when the asynchronous task is done;
///
/// - optionally, periodically check `self.cancelled` status, performing any clean-up
///   necessary and then ensuring that `completeOperation()` is called; or
///   override `cancel` method, calling `super.cancel()` and then cleaning-up
///   and ensuring `completeOperation()` is called.
public class AsynchronousOperation : NSOperation {
    override public var asynchronous: Bool { return true }
    private let stateLock = NSLock()
    private var _executing: Bool = false
    override private(set) public var executing: Bool {
        get {
            return stateLock.withCriticalScope { _executing }
        }
        set {
            willChangeValueForKey("isExecuting")
            stateLock.withCriticalScope { _executing = newValue }
            didChangeValueForKey("isExecuting")
        }
    }
    private var _finished: Bool = false
    override private(set) public var finished: Bool {
        get {
            return stateLock.withCriticalScope { _finished }
        }
        set {
            willChangeValueForKey("isFinished")
            stateLock.withCriticalScope { _finished = newValue }
            didChangeValueForKey("isFinished")
        }
    }
    /// Complete the operation
    ///
    /// This will result in the appropriate KVN of isFinished and isExecuting
    public func completeOperation() {
        if executing {
            executing = false
        }
        if !finished {
            finished = true
        }
    }
    override public func start() {
        if cancelled {
            finished = true
            return
        }
        executing = true
        main()
    }
    override public func main() {
        fatalError("subclasses must override `main`")
    }
}
/// Asynchronous Operation base class
///
/// This class lets you perform asynchronous block operation. Make sure that the
/// the provided `block` calls `completeOperation`, or else this operation will 
/// never finish.
public class AsynchronousBlockOperation : AsynchronousOperation {
    private var block: ((AsynchronousOperation) -> ())?
    init(block: (AsynchronousOperation) -> ()) {
        self.block = block
        super.init()
    }
    override public func main() {
        block?(self)
    }
    override public func completeOperation() {
        block = nil
        super.completeOperation()
    }
}
extension NSLock {
    /// Perform closure within lock.
    ///
    /// An extension to `NSLock` to simplify executing critical code.
    ///
    /// - parameter block: The closure to be performed.
    func withCriticalScope<T>(@noescape block: Void -> T) -> T {
        lock()
        let value = block()
        unlock()
        return value
    }
}

代码(正如您编写的那样)提出了一个"先有鸡还是先有蛋"的场景。试试这个:

var concurrentOperation: ((foo) -> bar)! //insert correct type annocation here
concurrentOperation = ABOConcurrentOperation {
    //use concurrentOperation here
}

最新更新