2017-01-10 4 views
0

私はSettingsViewControllerを持っており、各設定に必要な情報を定義する構造体を作成しました。なぜこのクロージャには私が期待する議論がないのですか?

///Represents a list of the options needed to populate a `SettingsTableViewCell` 
public struct Setting { 
    ///The image to use for the icon 
    var imageName : String 

    ///The text to display as the title of the setting 
    var title : String 

    ///Called when the switch is tapped. If no closure is supplied, the switch is hidden 
    var switchCallback: ((_ status: Bool)->())? 
} 

ビューコントローラは、後でテーブルビューで使用するためにこれらの設定の配列を保持します。 1の例を以下に提供されています。私がコンパイルしようとすると

let options : [Setting] = 
[ 
    Setting(imageName: "notifications", title: "Bump Notifications") {updateNotificationSetting($0)}, 
    ... 
] 

しかし、私はエラーを提示しています:(SettingsViewController)がどこから来ている

Cannot convert value of type '(SettingsViewController) -> (Bool) ->()' to expected argument type '((Bool) ->())?' 

誰かが、してください説明できますか?あなたができるなら、私はそれを修正するために何を変える必要がありますか? SSCCEについては


、以下を参照:

import UIKit 

///Represents a list of the options needed to populate a `SettingsTableViewCell` 
public struct Setting { 
    ///The image to use for the icon 
    var imageName : String 

    ///The text to display as the title of the setting 
    var title : String 

    ///Called when the switch is tapped. If no closure is supplied, the switch is hidden 
    var switchCallback: ((_ status: Bool)->())? 
} 



@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate { 

    var window: UIWindow? 

    let options : [Setting] = 
    [ 
     //Error is on the following line 
     Setting(imageName: "notifications", title: "Bump Notifications") {isOn in updateSetting(isOn)}, 
    ] 

    func updateSetting(isOn : Bool) { 

    } 

} 
+0

あなたのクローズの初期化のどこかで。 – Sulthan

+0

閉包に明示的な 'self'はありませんが(上記参照)、' updateNotifications($ 0) 'の前に暗黙のものがあると思います。この場合、その関数をどのように呼び出すかに関する提案はどうですか? –

+0

関連していませんが、Swift 3では、コールバッククロージャのすべてのパラメータラベルが削除されています。コールバックのシグネチャは、エラーメッセージに表示されているように '(Bool) - >()'のみであり、 'status'はまったく使用されません。 – vadian

答えて

2

あなたSetting初期化子内の閉鎖がselfをキャプチャしています。ただし、Swiftのselfは、オブジェクトのすべてのプロパティが初期化された後、つまりlet optionsが初期化された後にのみ使用できます。明示的な型: [Setting]現在宣言のために必要とされる

public struct Setting { 
    var imageName : String 
    var title : String 
    var switchCallback: ((_ status: Bool)->())? 
} 

class MyClass { 
    lazy var options: [Setting] = [ 
     Setting(imageName: "x", title: "X") { [unowned self] in self.updateSetting(isOn: $0)} 
    ] 

    func updateSetting(isOn : Bool) {} 
} 

注:円を破る

一つの方法は、特性の遅延初期化を使用することです。

リリースサイクルを中断するには、[unowned self]または[weak self]を使用する必要があります(コメントに@robを感謝します)。

+0

@Rob私のテストでは参照サイクルはなく、オブジェクトの割り当てが解除されましたが、確かに '[unowned self]'を置くことになります。 – Sulthan

+0

@Robああ、そうだよ! – Sulthan

0

But (a) you have to have an explicit reference to self in the closure (e.g. self.updateNotificationSetting); and (b) to do that, you can only do that if you make it lazy var rather than let (allowing it to now resolve self).

私はキーワードlazy varでこの作業を取得することができませんでしたが、これは私がこの問題を解決するために必要な情報を提供しました。私は本質的に自分の怠惰なvarを作っただけで、配列を使う直前にインスタンス化することになります:

private var options : [Setting]! 


... 

if options == nil { 
     options = [ 
      Setting(imageName: "notifications", title: "Bump Notifications") {isOn in self.updateNotificationSetting(isOn: isOn)}, 
      Setting(imageName: "automatic_check_in", title: "Automatic Check In") {isOn in self.updateAutomaticCheckInSetting(isOn:isOn)}, 
      Setting(imageName: "logout", title: "Logout", switchCallback:nil) 
     ] 
    } 
+0

私は、「自己」への「弱い」または「所有されていない」参照を提案します。 'Setting(imageName:" automatic_check_in "、title:"自動チェックイン "){[weak self] isOn in self?updateAutomaticCheckInSetting(isOn:isOn)} 'です。 – Rob

関連する問題