Objective-CからSwiftぞのプロゞェクトの翻蚳に぀いお

こんにちは芪愛なる読者。



過去6か月間に出版のヒントで取り䞊げられた最も燃えおいるトピックの䞭で、Swiftプログラミング蚀語には特別な堎所がありたす。 欧米の開発者からの倧きな関心ず、このテヌマに関する本の豊富な本で、蚀語はただかなり生々しく芋えたす。 したがっお、新しい蚀語の関連性に぀いお調査し、「Programming iOS 8Dive Deep into Views、View Controllers、and Frameworks」ずいう本の著者である壮倧なMatt Neuburgの投皿に粟通するこずを提案したす。 著者は、アプリケヌションの新しいApple蚀語ぞの翻蚳に぀いお詳现に説明し、「目が怖い-手がしおいる」こずを蚌明しおいたす。



幞せな読曞ず実り倚い実隓。



Objective-Cで蚘述されたアプリケヌションが既にある堎合は、Swiftでアプリケヌションを曞き盎しおみおください。 これは、Swift蚀語に粟通し、Swiftを詊しお、Swiftをメむンテクノロゞヌずしお遞択する準備ができおいるかどうかを自分で刀断する絶奜の機䌚です。 このような移行をいく぀かの実際のアプリケヌションで実行するこずができたした。この蚘事では、この経隓から収集したいく぀かの芳察結果を共有したいず思いたす。



ハむブリッドアセンブリ



もちろん、すべおのコヌドをすぐにSwiftに翻蚳する必芁はありたせん。 クラスごずに曞き盎す可胜性が非垞に高くなりたす。 Objective-Cで蚘述されたアプリケヌションのアセンブリにSwiftファむルを远加するずすぐに、このアセンブリはハむブリッドになりたす。 その䞭のいく぀かのクラスはObjective-Cに残り、他のクラスはSwiftで曞かれたす。 したがっお、すべおの宣蚀が䞡方の蚀語のコヌドで衚瀺されるようにする必芁がありたす。 この䜜業を始める前に、このような可芖性のメカニズムがどのように機胜するかを芋おみたしょう。

芚えおいるように、Objective-Cクラスの宣蚀は通垞、2぀の郚分に分かれおいたす。むンタヌフェむスセクションを含むヘッダヌファむル.hず、@ implementationセクションを含むコヌドファむル.mです。 .mファむルにクラス情報が必芁な堎合、そのクラスの.hファむルをむンポヌトしたす。

SwiftずObjective-Cコヌドの盞互可芖性は、次の芏則に基づいおいたす。.hファむルレベルで提䟛されたす。 可芖性には2぀の方向があり、それぞれ個別に考慮する必芁がありたす。



SwiftがObjective-Cを認識する方法



SwiftファむルをObjective-Cのアセンブリに远加する堎合、たたはObjective-CファむルをSwiftのアセンブリに远加する堎合、Xcodeはブリッゞヘッダヌを䜜成するように求めたす。 これは、プロゞェクトの䞀郚である.hファむルです。 デフォルトでは、その名前はアセンブリに代わっお䜜成されたすが、䞀般に任意であり、Objective-Cアセンブリの「リンクヘッダヌ」蚭定を同様に倉曎する堎合は倉曎できたす。

Objective-Cの.hファむルは、このリンクヘッダヌにむンポヌト#importされおいれば、Swiftに衚瀺されたす。



Objective-CがSwiftを認識する方法



リンクヘッダヌがある堎合、アセンブリを䜜成するず、すべおのSwiftファむルの察応するトップレベル宣蚀が自動的にObjective-Cに倉換され、DerivedDataフォルダヌの深い堎所にあるこのタヌゲットアセンブリのIntermediatesディレクトリに隠しリンクヘッダヌを䜜成するために䜿甚されたす。 この非衚瀺ヘッダヌは、タヌミナルりィンドりに入力された次のコマンドを䜿甚しお最も簡単に衚瀺できたす。



$ find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h"
      
      







これにより、非衚瀺のリンクヘッダヌの名前が認識されたす。 たたは、タヌゲットアセンブリの[補品モゞュヌル名]蚭定を衚瀺たたは倉曎しおみおください。 非衚瀺のリンクヘッダヌの名前は、ここで指定した補品名に基づいお䜜成されたす。



Swift宣蚀は、これらのSwiftファむルが衚瀺されるすべおのObjective-Cファむルにこの隠しリンクヘッダヌをむンポヌト#importするこずを条件に、Objective-Cファむルに衚瀺されたす。



状況は、.mファむルの䞊郚の非衚瀺リンクヘッダヌが正確にむンポヌトされる堎所から倧幅に倉化する可胜性がありたす。 䞀般的なアラヌムは、「䞍明なタむプ名」のコンパむル゚ラヌの出珟です。䞍明なタむプはObjective-Cで宣蚀されたクラスです。 この問題を解決するには、非衚瀺のリンクヘッダヌをむンポヌトする前に、䞍明な型宣蚀を含む.hファむルをObjective-Cファむルにむンポヌトする必芁がありたす。 そのような䜜業は、特に問題のObjective-Cファむルがこのクラスを知る必芁がない堎合は面倒なこずがありたすが、この方法で問題を本圓に解決し、その埌コンパむルを続行できたす。



順を远った説明



倉曎を行う前に、gitで新しいブランチを䜜成したす。 次に、Objective-CからSwiftにクラスを1぀ず぀転送したす。 次のアルゎリズムに埓っおこれを行いたす。



  1. Swiftに倉換する.mファむルを遞択したす。 Objective-CはSwiftクラスを継承できないため、サブクラスから始めお、Objective-Cでサブクラスずクラス自䜓の䞡方を定矩する必芁がありたす。 アプリケヌションデリゲヌトクラスは最埌に翻蚳されたす。
  2. この.mファむルをタヌゲットアセンブリから削陀したす。 これを行うには、.mファむルを遞択し、ファむルむンスペクタヌを䜿甚したす。
  3. 察応する.hファむルをむンポヌトするすべおのObjective-Cファむルで、importステヌトメントを削陀し、代わりに非衚瀺のリンクヘッダヌをむンポヌトしたす。 隠しリンクヘッダヌをこのファむルに既にむンポヌトしおいる堎合は、この手順を繰り返す必芁はありたせん。
  4. 察応する.hファむルをリンクヘッダヌにむンポヌトする堎合は、importステヌトメントを削陀したす。
  5. このクラスの.swiftファむルを䜜成したす。 タヌゲットアセンブリに远加されおいるこずを確認しおください。
  6. .swiftファむルで、クラスを宣蚀し、.hファむルで公開されたすべおのメンバヌのスタブ宣蚀を配眮したす。 このクラスがCocoaプロトコルに準拠する必芁がある堎合は、それらを受け入れたす。 たた、このプロトコルのすべおの必須メ゜ッドにスタブ宣蚀を提䟛する必芁がありたす。 このファむルが、Objective-Cのタヌゲットアセンブリでただ宣蚀されおいる他のクラスも参照する必芁がある堎合は、それらの.hファむルをリンクヘッダヌにむンポヌトしたす。
  7. これでプロゞェクトがコンパむルされたす もちろん、.swiftファむルにはただ実際のコヌドがないため、機胜したせん。 しかし、これは本圓に問題なのでしょうか だから、ゞャヌクのためのビヌル
  8. ここで、.swiftファむルにコヌドを蚘述したす。 結果が慣甚的ではない堎合でもSwift、元のObjective-Cファむルのコヌドを1行ず぀翻蚳するこずを奜みたす。
  9. この.mファむルのコヌドがSwiftに完党に倉換されたら、ビルドしお実行し、テストしたす。 ランタむムがこのクラスを芋぀けるこずができないこずを誓う堎合特に同時にクラッシュする堎合、nib゚ディタヌでそれぞのすべおのリンクを探し、IDむンスペクタヌでクラス名を再入力したすたた、倉曎を蚭定するためにTabを抌したす 。 すべおを保存しお再詊行しおください。
  10. 次の.mファむルぞ 䞊蚘のすべおの手順を繰り返したす。
  11. 他のすべおのファむルが翻蚳されたら、アプリケヌションデリゲヌトクラスを翻蚳したす。 この段階で、Objective-Cにタヌゲットアセンブリにファむルが残っおいない堎合は、main.mファむルアプリデリゲヌトクラス宣蚀属性の@UIApplicationMain属性に眮き換えたすず.pchファむルプリコンパむル枈みヘッダヌを削陀できたす。




すべおのコヌドをSwiftに翻蚳する必芁があるずは思わないでください。 䞀郚のセクションは、Objective-Cに残すほうがよい堎合がありたすが、これは完党に正垞です。 実際、SwiftがアクセスできないCocoa APIの詳现があるため、Objective-Cにいく぀かのコヌドを残す必芁がありたす。 たずえば、C関数をSwiftたたは関数ポむンタヌに曞き蟌むこずはできないため、Objective-Cヘルパヌメ゜ッドなしでCGPatternCreateたたはAudioServicesAddSystemSoundCompletionを呌び出すこずはできたせん。 AppearanceWhenContainedInメ゜ッドは、Swiftから呌び出すこずもできたせん。



䞀方、Swiftでは䜿甚できないperformSelectorメ゜ッドのいずれかを䜿甚するコヌドは、Objective-Cにすぐに残すこずができたすが、遅かれ早かれ、これらのメ゜ッドをSwiftのコヌドに眮き換えるための回避策を考え出す必芁がありたす。



Swiftを詊しおみたしょう



おめでずうございたす これで、アプリケヌションの党郚たたは䞀郚がSwiftで䜜成されたした。 しかし、私のすべおの掚奚事項に埓えば、この段階ではアプリケヌションはただ「速すぎ」たせん。 結局、私たちは䞻にコヌドを実行しようずしたした。 これですべおが機胜するようになったので、コヌド自䜓に戻っおコヌドをより慣甚的にするこずができたす。 Objective-Cで耇雑に、たたは厄介に解決されたいく぀かのタスクは、Swiftで実装されたよりクリヌンで優れたものである堎合がありたす。



もちろん、可胜な限り、ネむティブのSwiftタむプに切り替える必芁がありたす。 NSStringずNSMutableString、NSArrayずNSMutableArray、およびNSDictionaryずNSMutableDictionaryなどの䞍倉/可倉型のペアは、ネむティブのSwift型String、Array、Dictionaryに眮き換えるこずができたす。 たた、これらのタむプに付属しおいた耇雑なトリックのいく぀かはもう必芁ないこずがわかりたす。 そのため、配列にはむンスタンスメ゜ッドmap、filter、reduceがありたす。 圌らはあなたにずっお非垞に圹立぀でしょう。



たずえば、私のアプリケヌションの1぀に、デヌタがセクションごずに分割されお衚瀺される衚圢匏のビュヌがありたした。 システム内レベルでは、このデヌタは配列の配列に蚘録されたす。各サブ配列は、特定のセクションの衚圢匏の行を衚す行で構成されたす。 テヌブルを怜玢できたす。次に、ナヌザヌが怜玢フィヌルドに入力したサブストリングを含たない行を怜玢しお削陀したす。 セクション自䜓には觊れたせんが、行を削陀するずきに䞀郚のセクションが完党に空になっおいる堎合は、このセクションの配列党䜓を完党に削陀したす。 これはObjective-Cで行われた方法ですsbはUISearchBarです



  NSPredicate* p = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *d) { NSString* s = obj; NSStringCompareOptions options = NSCaseInsensitiveSearch; return ([s rangeOfString:sb.text options:options].location != NSNotFound); }]; NSMutableArray* filteredData = [NSMutableArray new]; for (NSArray* arr in self.sectionData) { NSArray* filteredArr = [arr filteredArrayUsingPredicate:p]; if (filteredArr.count) [filteredData addObject: filteredArr]; } self.filteredSectionData = filteredData;
      
      







最初に、NSPredicateを構成しお配列をフィルタヌしたす。 次に、配列の配列をルヌプ凊理しお、フィルタヌ凊理された各サブ配列のコンポヌネントを1぀ず぀空のNSMutableArrayに「分散」したす。 あなたはこのむディオムに粟通しおいるず確信しおいたす。 Swiftでは、NSPredicateも「配垃」のむディオムも、2぀の䞭間配列も必芁ありたせん マップずフィルタヌがあり、すべおの䜜業が単䞀のステヌトメントに収たりたす。



 self.filteredSectionData = self.sectionData.map { $0.filter { let options = NSStringCompareOptions.CaseInsensitiveSearch let found = $0.rangeOfString(sb.text, options: options) return (found != nil) } }.filter {$0.count > 0}
      
      







たた、コヌドがメッセヌゞ転送に関連するObjective-Cダむナミクスに䟝存しおいる堎所では、Swiftでは関数が最初のクラスのオブゞェクトであるため、このメカニズムがなくおも実行できたす。



䟋を考えおみたしょう。

蟞曞カヌドアプリケヌションには、ラテン語を衚すTermクラスがありたす。 倚くのプロパティを宣蚀したす。 各カヌドは1぀の甚語に察応し、各プロパティは個別のテキストフィヌルドに衚瀺されたす。 ナヌザヌが画面䞊のテキストフィヌルドのいずれかをクリックするず、むンタヌフェむスの珟圚の甚語を、ナヌザヌが遞択したプロパティによっお前の甚語ずは異なる次の甚語に倉曎する必芁がありたす。 したがっお、3぀のテキストフィヌルドすべおのコヌドは同じになりたす。 党䜓の違いは、画面に衚瀺する次の甚語を遞択するプロパティにありたす。



Objective-Cでは、このような䞊行性を衚珟する最も簡単な方法は、キヌず倀のペアを䜿甚するこずでしたgはクリックゞェスチャレコグナむザヌです



  NSInteger tag = g.view.tag; // the tag tells us which text field was tapped NSString* key = nil; switch (tag) { case 1: key = @"lesson"; break; case 2: key = @"lessonSection"; break; case 3: key = @"lessonSectionPartFirstWord"; break; } //       NSString* curValue = [[self currentCardController].term valueForKey: key];
      
      







これで、Swiftでキヌず倀のペアを匕き続き䜿甚できたす。 ただし、これには、TermクラスがNSObjectを継承する必芁があり、Objective-C / Cocoaのダむナミクス-文字列をプロパティ名に倉換する-Swiftの粟神ずは無関係です。 Swiftでは、匿名関数の単玔な配列を䜿甚しお、ラベルをメ゜ッド呌び出しに倉換するこずにより、同じダむナミクスを簡単に実装できるこずがわかりたす。



  let tag = g.view!.tag let arr : [(Term) -> String] = [ {$0.lesson}, {$0.lessonSection}, {$0.lessonSectionPartFirstWord} ] let curValue = arr[tag-1](self.currentCardController.term)
      
      







おわりに



Swiftの倚くのプロパティは、最初からコヌドの信頌性を高めるこずを目的ずしおいたす。



Objective-Cでプログラミングする際のよくある間違いは、むンスタンスプロパティを宣蚀するこずですが、元の倀に蚭定するのを忘れるこずです。 nilにメッセヌゞを送信しおも䜕も起こらないため、問題に気付かずに長時間䜜業できたす。 Swiftでは、すべおのむンスタンスプロパティの初期化が必芁です。 次に、悪名高いストロングタむピングSwiftに぀いお説明したす。 Objective-Cでは、配列の芁玠を掚枬するこずはかなり可胜ですが、Swiftでは、厳密に定矩された配列の芁玠タむプを指定する必芁がありたす。 これらのSwiftの特性ず戊おうずしないでください、圌らに感謝しおください 単にSwiftコヌドをコンパむルするように管理するだけであれば、すでに䜕かを孊びたす。 おそらく、あなたのコヌドは、そのような正確さがSwift蚀語の本質に組み蟌たれおいるずいう単玔な理由で正しいでしょう。



疑問がある堎合は、Swiftを詊しおみる䟡倀がありたす。もうheしないでください。 今こそ、Swiftを孊び、この蚀語を楜しむ時です。 Xcode 6.3のベヌタ版では、Swift 1.2がすでに利甚可胜であり、この蚀語が既に十分な成熟床に達しおいるこずを確認できたす。 Swiftは興味深くシンプルな蚀語であり、Objective-Cで䜜成されたアプリケヌションをすばやくすばやく翻蚳できたす。 結果のコヌドがどれほど明確で単玔になるか、驚くかもしれたせん。



All Articles