2017-11-14 16 views
0

Swiftで関数を実装しようとしているときに、特定の関数パラメータで型推論が破られたような問題が発生しました。他の言語のメモを取って、Swiftには、オブジェクトと、前のオブジェクトと同じ型の別のオブジェクトを返すブロックという2つのパラメータを使用する関数を実装したかったのです。私はそうのようにそれを実装開始しました:それは私が決めたprepare(for:sender:)プロトコル拡張が自己によって制約された汎用クロージャで誤って推定されるタイプ

セグエ機能に苦しんでいるように見えたとして

func prepare<T>(_ object: T?, with block: ((T?) -> T?)) -> T? { 
    return block(object) 
} 

UITableViewControllerクラスの内部を使用しようとした後、私は、命名の問題を経験しましたこれを解決するために名前を変更するだけです(別の質問のために上記を保存します)。

func bootstrap<T>(_ object: T?, with block: ((T?) -> T?)) -> T? { 
    return block(object) 
} 

この名前は今のところできます。だから私はbootstrap(_:with:)オブジェクトとクロージャを取る関数を持って、オブジェクトの引数と同じ型のオブジェクトを返します。私は、例えばInt、特定のオブジェクトでこれを簡単に呼び出すことができます。もちろん

bootstrap(1, with: { $0 + 1 }) // returns 2 

しかしこれは、関数がためにそこにあるものではありません。

class ContactDetailHeaderView: UIView, Nibbable { 
    var user: User? 
} 

これはNibbableプロトコル以下のプロトコル拡張機能を使用して、ペン先からフェッチされる:だから、私は、単一の部材により小さなUIView由来のクラスを持って、その実際の意図する用途にそれを使用し

これにより
extension Nibbable where Self: UIResponder { 
    static func getRoot(withOwner owner: Any, options: [AnyHashable:Any]? = nil) -> Self? { 
     return self.nib.instantiate(withOwner: owner, options: options).first as? Self 
    } 
} 

は、我々はnibからオブジェクト(このクラスのための私達のUINibオブジェクト)を取得し、この場合にはContactDetailHeaderViewあるSelfとして、それをキャストすることができます。次に、以前に宣言した関数を使用してオブジェクトを設定することができます。私たちは、私はこの質問の目的のために凝縮しUITableViewController由来クラスContactDetailTableViewControllerのこの内部ん:

class ContactDetailTableViewController: UITableViewController { 
    var user: User? 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.tableView.backgroundView = bootstrap(ContactDetailHeaderView.getRoot(withOwner: self), with: { $0?.user = self.user }) 
    } 
} 

はしかし、我々は、この関数を呼び出すのエラーが表示されます。

Value of type 'UIView' has no member 'user' 

これは予想外です。私たちのgetRoot(withOwner:options:)関数はSelf、つまりContactDetailHeaderViewを返します。

はのは、名前付きパラメータと明示的に定義されたタイプで速記の引数を置き換えることにより、型推論を拡張してみましょう:

bootstrap(ContactDetailHeaderView.getRoot(withOwner: self), 
    with: { (header: ContactDetailHeaderView?) -> ContactDetailHeaderView? in 
     header?.user = self.user 
    } 
) 

確かに私たちのオブジェクトは今UIViewと解釈できるという方法はありませんか?さて、同じエラーが表示されます:

Value of type 'UIView' has no member 'user' 

なぜこのようなことが起こりますか? Xcodeでオートコンプリートをチェックしても、header引数は有効なアクセス可能なプロパティとしてuserのメンバーを示します。そして、なぜそれがbootstrap(_:with:)クロージャ内では機能しません

ContactDetailHederView.getRoot(withOwner: self)?.user = self.user 

getRoot(withOwner:options:)機能を使用すると、他の場所で期待される結果を生成しますか?これはバグですか?私は行方不明の何か他にありますか?

ご協力いただければ幸いです。

私はgistに十分なコードを添付して、問題を再生場所に再現します。簡単にするため、私は

(例えば、標準ライブラリで提供されていますStringに内部オブジェクトであるUserからuserタイプを変更)より管理しやすい何かで不要なビットの一部を置き換えますこの質問ことに注意してください。機能が何であるか、またはそれがなぜそれを行うのかについてはではなく、です。同じものを実装する方法はたくさんありますが、その多くははるかに優れています。私はこの関数を現在の形式で使用するかどうかにかかわらず、このコンパイラエラーを解決したいと思います。

+0

まあコンパイラは、自己が純粋 'UIView'サブクラスであることを考えているようです。私が間違って読んでいない限り、2番目から最後のコードスニペットでは、自分自身がどのクラスを参照しているかを指定しません。 'self'とは何か?' bootstrap'メソッドを実装するクラスに存在するユーザパラメータですか?ばかげた質問のように思えるかもしれませんが、あなたは 'header'と' ContactDetailHeaderView'クラスと、ユーザパラメータを要求する 'self'ポインタを持っています。 2つのうちの最初のものがありますので、私はあなたが何かを見落としている可能性があることを賭けています.. – murphguy

+0

右、私はここにコンテキストを含める必要があります。 @murphguy質問を編集させてください –

+0

今あなたの要点を見て心配しないでください – murphguy

答えて

2

Please keep in mind that this question is not about what the function does or why it does it. There are plenty of ways to implement the same thing, many of which are likely far better. I would like to solve this compiler error regardless of whether or not I even use this function in its current form.

これはあまりにも多くのオプションがあるためです。しかし、修正するのは簡単です(複雑すぎるため、理解するのは難しいです)。

bootstrapは、T?を返します。

{ (header: ContactDetailHeaderView?) -> ContactDetailHeaderView? in 
    header?.user = self.user 
} 

これは、Voidを返します。これは、タイプエンジンがすべての種類のウサギの穴を塞ぐ原因となります(特に、TT?になる可能性があります)。修正がTを返すことです:

あなたの主旨で
{ (header: ContactDetailHeaderView?) -> ContactDetailHeaderView? in 
    header?.user = self.user 
    return header 
} 

、これは次のようになります。

self.tableView.backgroundView = bootstrap(ContactDetailHeaderView.getRoot(withOwner: self), 
           with: { $0?.user = self.user; return $0 }) 
+0

ああ、私はそれがちょうどそのばかでなければならないことが分かっていた –

+0

ニースキャッチ笑! – murphguy

+1

内部クロージャは実際には 'T? 'を返すとは考えられません。それは '無効 'でなければなりません。私の指は私の脳のために速く動いていた。 –

関連する問題