2

クロージャーを取る関数にメソッドを渡す場合、someFunc(closure: someMethod) orsomeFunc() { [unowned self] in self.someMethod() }` のいずれかを使用できます。

最初のものは短いですが、強力な参照になります。この強い参照を避けながら使用するにはどうすればよいですか?

これは、漏れているものと良いものの両方を含むデモです: https://swiftlang.ng.bluemix.net/#/repl/581ccd3a0bdc661a6c566347

import Foundation

private var instanceCounter = 0

class Leak : NSObject {

    override init() {
        super.init()
        instanceCounter += 1
    }

    deinit {
        instanceCounter -= 1
    }
}

class OnFunctionLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil,
                                               usingBlock: doNothing)
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

class OnClosureLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil) { [unowned self] notif in
            self.doNothing(notif)
        }
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

var onFunctionLeak: OnFunctionLeak? = OnFunctionLeak()
onFunctionLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

instanceCounter = 0
var onClosureLeak: OnClosureLeak? = OnClosureLeak()
onClosureLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

短い選択肢は 26 行目にあり、 で置き換えるdoNothing{ [unowned self] notif in self.doNothing(notif) }、強い参照がなくなります。

何か案は?

4

2 に答える 2

2

この強い参照を避けながら使用するにはどうすればよいですか?

できません。

インラインで (使用時に) 定義された無名関数のみがキャプチャ リスト( など) を持つことができます[unowned self]。したがって、無名関数のみが、求めている機能を提供できます。で定義された関数はfunc単にそれを行うことはできません。

これは Swift に関する単なる事実です。

(おそらく根本的な理由があります。その理由はストレージに関係しているのではないかと思います。func関数は何らかの方法で静的に格納されます。しかし、インラインで定義された無名関数はそうではありません。渡された瞬間に生成されます。しかし、それは単なる推測であり、かなり漠然とした推測です。)

于 2016-11-04T20:25:37.107 に答える
0

マットは正しいです。強い参照なしで関数を使用する方法を見つけることができません。

var を使用して、クロージャーを関数内に直接記述してよりクリーンにすることができることがわかりました。実際にはクリーンではありません。

class OnVarLeak : Leak {

    var value = 0

    override init() {
        super.init()
        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnVarLeak"),
                                               object: nil,
                                               queue: nil,
                                               using: doNothing)
    }

    var doNothing: (Notification) -> Void {
        return { [unowned self] notif in
            self.value += 1
        }
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

そのように、強い参照がなく、「using: doSomething)」を実行できます。

プロジェクトに常にメモリ リークが残るため、Swift コンパイルでクロージャの代わりに関数を使用できるようにすることは、まだ安全ではないと思います。

于 2016-11-07T10:24:31.430 に答える