のファーストクラス関数ファーストクラス関数をサポートする言語では、他のオブジェクトや値と同じように関数やメソッドを使用できます。 それらを引数として渡したり、プロパティに保存したり、別の関数から返すことができます。 そのため、この言語は”ファーストクラスの市民”として機能している。Swiftはこのような関数の処理方法をサポートする最初の言語ではありませんが、通常はJavaScriptやLuaのようなより動的な言語で見られる機能です。 Swiftの堅牢な静的型システムとファーストクラスの関数を組み合わせることは非常に興味深い組み合わせになり、かなり創造的なことを行うことが

今週は、ファーストクラスの関数がSwiftで使用できるいくつかの異なる方法を見てみましょう!

Instabug:Instabugが自動的に各バグレポートに添付詳細なスタックトレース、ネットワークログとUIイベントを使用して、はるかに高速なバグ、クラッシュやその他の問 私と世界中の何千ものiOS開発チームの両方で使用されています。 無料で試してみて、コードの単一行だけでそれを統合します。

引数として関数を渡す

基本から始めましょう。 関数は値として使用できるので、引数として渡すことができることを意味します。 たとえば、サブビューの配列をビューに追加するとします。 通常、私たちはこのようなことをするかもしれません:

let subviews = subviews.forEach { subview in view.addSubview(subview)}

上記のコードは機能し、何も問題はありません。 しかし、ファーストクラスの関数を利用すると、実際にはその冗長性をかなり減らすことができます。

私たちができることは、addSubviewメソッドを(UIView) -> Void型のクロージャとして扱うことです(追加するビューを受け入れ、何も返さないため)。 これは、forEachが受け入れる引数の型と完全に一致します(型(Element) -> Voidのクロージャ、この場合はElement型はUIViewです)。 その結果、次のようにview.addSubviewを引数としてforEach呼び出しに直接渡すことができます:

subviews.forEach(view.addSubview)

それはかなりクールです! 😎ただし、このようなインスタンスメソッドをクロージャとして使用する場合、クロージャを保持している限り、インスタンスを自動的に保持していることに留意すべきことがあります。 これは、上記のようにエスケープしないクロージャ引数として関数を渡すときにはまったく問題ではありませんが、クロージャをエスケープするためには、

エスケープと非エスケープのクロージャ引数とキャプチャの詳細については、”Swiftクロージャでオブジェクトをキャプチャする”を参照してください。

引数として初期化子を渡す

素晴らしいことは、Swiftのファーストクラス関数として使用できる関数やメソッドだけでなく、このように初期化子を使

たとえば、画像ビューを作成したい画像の配列があり、それらの各画像ビューをスタックビューに追加したいとします。 ファーストクラスの関数を使用すると、mapの単純なチェーンを使用して上記のすべてを達成することができます。forEach:

images.map(UIImageView.init) .forEach(stackView.addArrangedSubview)

私がこのようにコードを構造化するのが好きなのは、それが非常に宣言的になるということです。 ネストされたforループの代わりに、単に結果を何にしたいかを宣言しています。 もちろん、宣言的でコンパクトなコードと可読性の間にはバランスが取れていますが、上記のような簡単な操作では、ファーストクラスの関数を利用す

“関数を使用した単純なSwift依存性注入”と”Swift単体テストでの時間移動”で、初期化子をクロージャとして渡すためのより多くの例とユースケースを見つけるこ

インスタンスメソッド参照の作成

ファーストクラス関数の素晴らしい世界に少し深く飛び込んでみましょう。 最も長い間私を困惑させていたことの1つは、静的メソッドを呼び出したいときにインスタンスメソッドの自動補完の提案が得られたという事実 XcodeでUIView.と入力して、私が何を意味するのかを確認してみてください。

最初はこれがXcodeのバグだと思っていましたが、それを調査することにしました。 型が持つ各インスタンスメソッドには、インスタンスを引数として渡すことで、そのインスタンスメソッドをクロージャとして取得できる対応す

たとえば、指定されたUIViewインスタンスのremoveFromSuperviewメソッドへの参照を取得するには、次のように使用できます:

let closure = UIView.removeFromSuperview(view)

上記のクロージャを呼び出すことは、view.removeFromSuperview()を呼び出すこととまったく同じですが、これは興味深いことですが、本当に便利ですか? のは、この機能を使用すると、実際にいくつかのかなりクールな結果につながることができますいくつかのシナリオを見てみましょう。

Linux上のXCTest

Appleのフレームワークの一つがこの機能を使用する一つの方法は、Linux上でXCTestを使用してテストを実行するときです。 Appleのプラットフォームでは、XctestはObjective-Cランタイムを使用して特定のテストケースのすべてのテストメソッドを検索し、それらを自動的に実行します。 しかし、LinuxではObjective-Cランタイムがないので、テストを実行するために少し定型文を書く必要があります。

まず、テスト名と実行する実際のメソッドの間のマッピングを含む静的なallTests辞書を宣言する必要があります。

次に、上記の辞書をXCTMain関数に渡してテス:

XCTMain()

内部では、これは静的な同等のものを使用してインスタンスメソッドを抽出できるという機能を使用しています。 かなり賢い! 👍

この機能がなければ、次のように記述する必要がありました。

シーケンス内の各要素でインスタンスメソッドを呼び出す

自分自身をスピン 別のオブジェクトのインスタンスメソッドをforEachの引数として渡すことができたのと同じように、シーケンス内のすべての要素に実行させたいインスタ

たとえば、スーパービューから削除したいサブビューの配列があるとしましょう。 代わりにこれを行う必要があります:

for view in views { view.removeFromSuperview()}

私たちは代わりにこれを行うことができれば、それはクールではないでしょうか:

views.forEach(UIView.removeFromSuperview)

良いニュースは、これらの静的に参照されるインスタンスメソッドのいずれかを受け入れるSequenceに小さな拡張機能を作成することだけです。 それらは関数を生成する関数であるため(Functionception! 😂)その型は常に(Type) -> (Input) -> Outputになるので、拡張機能では、そのような型のクロージャを受け入れるforEachオーバーロードを作成できます。

任意のシーケンスの各メンバーでインスタン 🎉

Objective-C

なしでtarget/actionを実装するもう一つの例を見てみましょう。 UIKitでは、ボタンのクリックを観察することからジェスチャーに応答することまで、ターゲット/アクションパターンは非常に一般的です。 以前に説明した保持サイクルの問題を心配することなく、インスタンスメソッドをコールバックとして簡単に使用できるので、私は個人的にこのパターただし、UIKitでtarget/actionが実装される方法はObjective-Cセレクタに依存しています(そのため、プライベートアクションメソッドに@objc注釈を付ける必要があります)。 カスタムビューの1つにターゲット/アクションパターンを追加し、Objective-Cセレクタに依存せずにそれを実行したいとしましょう。 それは多くの仕事のように聞こえ、物事を非常に複雑にするかもしれませんが、ファーストクラスの関数のおかげで-それは非常に簡単です! 😀

まず、Actiontypealiasを、指定された型と入力のインスタンスメソッドを返す静的関数として定義しましょう:

typealias Action<Type, Input> = (Type) -> (Input) -> Void

次に、ビューを作成しましょう。 ユーザーが描画アプリで色を選択できるようにするColorPickerを作成し、ターゲット&アクションを追加するメソッドを追加します。 すべての観測値をクロージャとして追跡し、クロージャが実行されるたびに、指定されたターゲットのインスタンスメソッドを生成して実行します。

クールなことは、実際には上記のファーストクラス関数をさらに使用できるということです。 OptionalmapAPIを使用すると、インスタンスメソッドを生成し、次のように一度に呼び出すことができます:

observations.append { view in target.map(action)?(view)}

最後に、新しいtarget/action APIをCanvasViewControllerで使用してみましょう。 Target&アクションをUIButtonまたはUIGestureRecognizerに追加するのと同じように、

Type safe targets&アクションをObjective-Cセレクタやメモリリークのリスクなしで、わずか数行のコードを使用して実行することができます。 ▲

このスポンサーをチェックアウトすることにより、サンデルによってSwiftをサポ:

Instabug:Instabugが自動的に各バグレポートに添付詳細なスタックトレース、ネットワークログとUIイベントを使用して、はるかに高速なバグ、クラッシュやその他の問 私と世界中の何千ものiOS開発チームの両方で使用されています。 無料で試してみて、コードの単一行だけでそれを統合します。

結論

ファーストクラスの関数は非常に強力な機能です。 関数やメソッドをはるかに動的な方法で使用できることで、かなり興味深い結果を得ることができ、特定の種類のApiを実装するときに本当に役立

しかし、ベンおじさんの有名な言葉では、大きな力で大きな責任が来ます。 これらの種類の機能とその仕組みについて学ぶことは非常に便利だと思いますが、それらを使用する際には拘束を行使することも重要です。 私たちの目標は、常に使いやすく使いやすいApiを作成し、読みやすいコードを書くことです&maintain。 ファーストクラスの関数は間違いなく私たちがその目標を果たすのに役立ちますが、あまりにも遠くに取られた場合、それはまた正反対につな いつものように、私のお勧めは、実験し、これらの機能を試して、自分のコードで使用できるかどうか、どのように使用できるかを自分で確認することです。

コメントを残す

メールアドレスが公開されることはありません。