2016-07-07 8 views
0

に弱い可能にしようとしたとき、私はブロックを含む初期化子と私のNSOperationサブクラスを作成しています:「独自の初期値内で使用される変数」初期化

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

残念ながら、これは私がいつものように動作しません。エラーメッセージVariable used within its own initial valueを私には分かりますが、どうすれば内部の弱い参照としてconcurrentOperationを実現できますか?

+0

http://stackoverflow.com/a/30523666/3141234 – Alexander

+0

私は操作が解除されないよう、サイクルを維持し得るかあるかのように思える - 答えに私のコメントを参照してください@AMomchilovの – swalkner

+0

振り返ってみると、明らかに問題の閉鎖これを解決する方法は、操作そのものをパラメータとして自身への参照を渡すことです。私の答えは以下の改訂された議論を参照してください。 – Rob

答えて

0

コードは(あなたが書いたように)「チキンか卵」のシナリオを提示します。これを試してみてください:

var concurrentOperation: ((foo) -> bar)! //insert correct type annocation here 

concurrentOperation = ABOConcurrentOperation { 
    //use concurrentOperation here 
} 
+0

しかし、私は 'concurrentOperation'を使用していれば操作は解放されません。 – swalkner

+0

@swalkner必ずしもそうではありません。クローズが再び呼び出されることなく終了する場合、ARCは参照をクリーンアップする必要があります。しかし、それをテストしてください。 – Alexander

1

あなたはブロックでの動作への参照が必要な場合は、あなたが閉鎖にパラメータとして渡す必要があり、その後、あなたが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) 

そして、私は標準閉鎖することクロージャを定義した:あなたはdeinitで何かを印刷し、あなたのサブクラスを持っている場合

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. 

/// a subclass that will just confirm that `deinit` is called 

class ABOConcurrentOperation: AsynchronousBlockOperation { 
    deinit { 
     print("deinit") 
    } 
} 

あなたはそれが起こるのを見るでしょう:

2016年7月7日21時20分54秒0000:操作
2016年7月7日21時21分01秒0000を起動する:あなたの参考のために操作
deinit

を終え、これはサンプルです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 
    } 
} 
関連する問題