早く! プロトコル指向

みなさんこんにちは!

いいえ、これは「Swiftとその機能を満たす」スタイルの別の投稿ではなく、実際のアプリケーションと微妙な点についての短いエクスカーションです。Appleの新しい言語のプロトコル指向の性質により、素敵で便利なことができます。

画像





habr-katの下を見た人への特別な挨拶。 最近、私は「Swift」で多くを開発しなければなりませんでしたが、同時にオブジェクトCには多くの荷物があり、新しい言語で実装するのがはるかに簡単でエレガントであると理解したコードで何かを表現したいという要望があります。



注意 :この記事は詳細な教材ではありませんが、個人的に私に感銘を与えた実用的なポイントを表し、私はそれらを共有することにしました。



この記事で何を期待しますか?





プロトコルの力とは何ですか?



まず、誰もがプロトコルメカニズムを知っているため、1つのオブジェクトでさまざまなタイプのプロトコルの多重継承を実装できます。 継承は、n番目のステップの相続人のチェーンでは、他のオブジェクトに共通する新しい動作を「注ぐ」または「追加する」ことができないという事実に限定されます。

次に、Swiftでは、指定されたプロトコルのデフォルト実装(デフォルト実装)を追加できます。 さらに、プロトコルには、それを継承するオブジェクトのクラスまたはタイプに応じて、いくつかのデフォルト実装があります。

第三に、プロトコルはプロトコルから継承できます。

第4に、プロトコルはクラス(クラス)だけでなく、構造(構造)と列挙(列挙)によって継承できます。

第5に、プロトコルはプロパティを追加できます。

第6に、システムプロトコルのデフォルトの実装を追加できます。必要に応じて、特定のクラスで既にオーバーライドできます。

結論として、プロトコルを使用すると、異なるクラスおよび構造でコードを再利用可能にすることができます。 それらに共通のタスクを実装し、それらを必要なファイルにデコレーターとして接続できます。

たとえば、各プロジェクトでUIViewのクリックを処理する必要があるため、余分なコードを記述しないたびに、独自のTappableクラスを作成します(コードはこちらです

個人的には、プロトコルを継承する際に、継承されたメソッドとプロパティが明確に見えるようにするために、いくつかの規則を見逃しています(Rubyでこれを聞いた)。



protocol FCActionProtocol { var actionButton: UIButton! {get set} func showActionView() } class FCController: FCActionProtocol { var actionButton: UIButton! // FCActionProtocol convenience func showActionView() {} }
      
      





actionButtonshowActionView()が自動的に生成された領域で置き換えられるようにします。

Swift 3.0で待ちます



拡張機能で追加のクラスの動作を飾ります



したがって、理論から実践まで:ライフケース番号1。

コントローラーの表示サイクルのロジックと、モデルを表示に転送するロジックがあると想像してください。 突然、メールクライアントを表示するためのロジックを合わせる必要がある新しいコントローラー拡張機能があります。 プロトコルを使用すると、これは簡単です。



 class MyViewController: UIViewController { // a lot of code here } extension MyViewController: MFMailComposeViewControllerDelegate { func showMailController() { let mailComposeViewController = configuredMailComposeViewController() if MFMailComposeViewController.canSendMail() { self.presentViewController(mailComposeViewController, animated: true, completion: nil) } } func configuredMailComposeViewController() -> MFMailComposeViewController { let controller = MFMailComposeViewController() controller.mailComposeDelegate = self return controller // customize and set it here } // MARK: - MFMailComposeViewControllerDelegate func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {} }
      
      





Swiftのobj-cとは異なり、 MyViewControllerクラスの拡張で新しい継承可能なプロトコルを指定し、その動作を実装できることは非常に喜ばしいことです。



プロトコルとデフォルトの実装を使用して再利用可能な要素を作成します



ケースNo. 2:最近、2つの画面上のアプリケーションに同じボタンがあり、同じシナリオに至りました-アクション付きのactionSheetを表示し、その1つはメールクライアントを示しました。 技術的なタスクは、接続と依存関係の複雑さの度合いが最小限になるように、実装と内部のすべてのロジックを備えたプロトコルを実装することでした。 プロジェクトのコードは次のとおりです。



 protocol FCActionProtocol { var actionButton: UIButton! {get set} var delegateHandler: FCActionProtocolDelegateHandler! {get set} mutating func showActionSheet() func showMailController() } class FCActionProtocolDelegateHandler : NSObject, MFMailComposeViewControllerDelegate { var delegate: FCActionProtocol! init(delegate: FCActionProtocol) { super.init() self.delegate = delegate } func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) { controller.dismissViewControllerAnimated(true, completion: nil) } } extension FCActionProtocol { mutating func showActionSheet() { delegateHandler = FCActionProtocolDelegateHandler(delegate: self) let actionController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet) actionController.addAction(UIAlertAction(title: NSLocalizedString("ActionClear", comment: ""), style: .Default) { (action) in }) actionController.addAction(UIAlertAction(title: NSLocalizedString("ActionWriteBack", comment: ""), style: .Default) { (action) in self.showMailController() }) if let controller = self as? UIViewController { controller.presentViewController(actionController, animated: true) {} } } func showMailController() { if MFMailComposeViewController.canSendMail() { let controller = MFMailComposeViewController() controller.mailComposeDelegate = delegateHandler (self as! UIViewController).navigationController!.presentViewController(controller, animated: true, completion: nil) } } }
      
      





注意! コードの考え方は、ボタン( actionButton )を含むプロトコルFCActionProtocolがあり、クリックするとアクション( showActionSheet )のあるシートが表示されるというものです。 内部では、シート要素をクリックすると、メールクライアント( showMailController )が表示されます。 この呼び出しのロジックと処理がプロトコルを継承するクラスに実装されないようにするため、拡張機能内で作成されたいくつかの抽象的なdelegateHandlerエンティティを使用して内部でデフォルトの実装を行い、メールクライアントのデリゲートメソッドはFCActionProtocolDelegateHandlerクラスインスタンスによって処理されます



その結果、この再利用可能なアクションリストを追加する難しさは次のとおりです。



 class FCMyController: FCActionProtocol { var actionButton: UIButton! // convenience FCActionProtocol var delegateHandler: FCActionProtocolDelegateHandler! // convenience FCActionProtocol }
      
      





内部のすべてのロジック。 初期化してボタンを追加するだけです。 私の意見では、それは美しく簡潔になりました。



プロトコルと列挙型-便利です



ライフケース#3:私たちのチームはオンライン航空券サービスを行いました。 モバイルクライアントはサーバーと密接に通信し、APIの呼び出しが行われるさまざまなシナリオがあります。 条件付きで検索、チケット予約、支払いに分けます。 これらの各プロセス(サーバー、クライアント、通信プロトコル、データ検証など)でエラーが発生する場合があります。 サーバーから500番目を予約または検索する際にまだ心配しない場合、たとえば内部サーバーから支払いを行う場合、データは既に支払いゲートウェイに送られ、クライアントは単にエラーを表示できず、銀行から引き落とすことができます。カード。

ここで、プロトコルにより、非常にエレガントなコードを作成できます。



 protocol Critical { func criticalStatus() -> (critical: Bool, message: String) } enum Error { case Search(code: Int) case Booking(code: Int) case Payment(code: Int) } extension Error : Critical { func criticalStatus() -> (critical: Bool, message: String) { switch self { case .Payment(let code) where code == 500: return (true, "Please contact us, because your payment could proceed") default: return (false, "Something went wrong. Please try later.") } } }
      
      





次に、コードを取得し、すべてがどれほど悪いかを評価します。



 let error = Error.Payment(code: 500) if error.criticalStatus().critical { print("callcenter will solve it") }
      
      





残念なことに、このプロジェクトは、Swiftとの互換性を確保するための多数のハックを持つ大きなObjective-Cレイヤーを表しています。

言語のすべての機能を使用して、次のプロジェクトを実装できることを願っています。



Ps Hope初心者がSwiftとプロトコル開発アプローチに興味を持つことを願っています。 たぶん中間から誰かが彼が使用しなかったいくつかのトリックに気づくでしょう。 そして、先輩たちは彼らの秘密とベストプラクティスを批判してコメントで共有することはありません。 どうもありがとう。



All Articles