質問: dataList } else { //検索文字列を含むデータを検索結果配列に追加する。 for data in dataList { if data.containsString(testSearchBar.text!) { searchResult.append(data) } } } //テーブルを再読み込みする。 testTableView.reloadData() } } } ```
回答: まず、tonyさんには、SwiftとXcodeを使って、ソフトウェア開発、プログラミングをする上で、身に付けておかなければならない知識がいくつかあります。質問に対する回答に入る前に、その必須な知識の話をさせてもらいます。 第一。プログラミング言語Swiftは、2014年に最初のバージョンがリリースされた、新しい言語です。そして2020年の今もまだ開発の途中であり、さまざまな拡張と改変を繰り返しています。拡張と改変には、細かなものも多数ありますが、ときに大規模な改変、180度方針転換した仕様変更がなされるときもありました。 `containsString(_ string: String)` こういうメソッド名が `contains(_ str: String)` に変更されるということは、ざらにあることで、数年前に書かれたサンプルコードが、最新バージョンのXcodeでは、まったく通用しない、「containsString をもっていない」ということが生じます。 なので、初めて使うプロパティ、メソッドなどは、かならずXcode付属のドミュンメントとリファレンスにあたる必要があります。英語の勉強をする時に、初めてみる英単語は、必ず英和辞書を引いてみるのと、同じことですね。 第二。Apple製品の開発言語の標準は、Swiftですが、2014年以前それはObjective-Cでした。Objeective-CがApple(以前のNext社の時代)の開発言語になったのが1985年のことですので、相当に古い言語といえます。が、iOSの基本フレームワーク(Foundation、UIKit)はこのObjective-Cで記述されており、SwiftによるiOSソフトウェアの開発は、Objective-Cとの互換性の上に成り立っています。 `let dataList: [String] = []` のプロパティ宣言にあることから、 ``` for data in dataList { if data.containsString(testSearchBar.text!) { searchResult.append(data) } } ``` の箇所の変数`data`は、`String`型です。しかし、構造体`String`のリファレンスをいくら探しても、 `containsString(_ string: String)`も`contains(_ str: String)`というメソッドも見つかりません。このメソッドは、じつはクラス`NSString`にあります。`NSString`は、そもそもObjective-Cのクラスであって、Swiftの構造体`String`は、それと互換性があることを保証されています。 `if data.containsString(testSearchBar.text!)` を `if (data as NSString).contains(testSearchBar.text!)` とすると、Xcodeの入力補完のリストに出てくるようになるでしょう。`as`は、型キャストを行う時に使う演算子です。 第三。Objective-CとSwiftの互換は、将来にわたって保証されているものではありません。現時点で、SwiftUIという、Objective-Cがまったく絡まない、Swift独自のフレームワークが実用化されようとしています。これからは、Swiftだけで完結するコード記述を前提にすることが必要になってくるでしょう。 > > containsString をつかわない検索機能として filter というものもみたのですが どちらをつかったほうがいいでしょうか? > > > 使うとしたら、プロトコル`StringProtocol`にある、 func contains(_ other: T) -> Bool where T : StringProtocol を採用するべきでしょう。 「プロトコル」という言葉(というか概念)は、学習済みですか?もし初見だとしたら、Swift(じつはObjective-Cにおいても同様)の言語体系の根幹をなす、重要な概念なので、すこし腰を落ち着けて、じっくり学習すべきところです。 が、今回のご質問に即してみていくなら、プロトコルは、クラスや構造体などの型を構成する部品のようなものと、とらえる事ができます。正確ではありませんが、ひとつの面だけ見れば、そういう事ができます。 順を追って見ていきます。まず、文字列`"あいうえお"`に、文字列`"あい"`が含まれるか、調べたいと思います。それができる関数、メソッドがないか、探します。対象が文字列ですから、`String`型のメソッドにないか、リファレンスを探します。「含まれる」という意味の英単語になっているメソッドを探します。しかし、適当な物が見つかりません。次に、`String`のリファレンスの最後にある「Conforms To」(準拠している)に列挙してあるプロトコルをひとつひとつあたってきます。そうすると、プロトコル`StringProtocol`に、メソッド`func contains(_ other: T) -> Bool where T : StringProtocol`というのが見つかりました。どうやらこれが使えそうです。構造体、クラスにないメソッドでも、準拠しているプロトコルにあるメソッドなら、その構造体でも、そのメソッドが使えるのです。 ``` let aiueo = "あいうえお" if aiueo.contains("あい") { print("Contains") } ``` このような流れで、目的のメソッド、あるいはプロパティなどを見つけていくのです。 質問からは離れますが、一点だけ指摘しなければいけないところがあります。 `let dataList: [String] = []` このようにプロパティを`let`で宣言してしまうと、要素数0の配列として固定されてしまい、なにをどうやっても要素数0から変更ができません。`let`と`var`の違いを、しっかり学習する必要があります。