

Swiftにて検索機能の実装において

Tab Controllerに追加したViewController（SearchViewControroller）に以下のコードをもたせても data は
containsString をもっていない とでてしまいます

どうしたらいいでしょうか？

追記

containsString をつかわない検索機能として filter というものもみたのですが どちらをつかったほうがいいでしょうか？

[code]

    import UIKit
    
    class SearchViewControroller: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
    
        @IBOutlet weak var testTableView: UITableView!
        @IBOutlet weak var testSearchBar: UISearchBar!
    
        let dataList: [String] = []
    
        //検索結果配列
        var searchResult = [String]()
    
        //最初からあるメソッド
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //デリゲート先を自分に設定する。
            testSearchBar.delegate = self
    
            //何も入力されていなくてもReturnキーを押せるようにする。
            testSearchBar.enablesReturnKeyAutomatically = false
    
            //検索結果配列にデータをコピーする。
            searchResult = dataList
        }
    
        //データを返すメソッド
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return dataList.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let searchcell = tableView.dequeueReusableCell(withIdentifier: "searchcell")!
            searchcell.textLabel?.text = dataList[indexPath.row]
    
        //データの個数を返すメソッド
        func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int {
            return searchResult.count
        }
    
    
    
        //検索ボタン押下時の呼び出しメソッド
        func searchBarSearchButtonClicked(searchBar: UISearchBar) {
            testSearchBar.endEditing(true)
    
            //検索結果配列を空にする。
            searchResult.removeAll()
    
            if(testSearchBar.text == "") {
                //検索文字列が空の場合はすべてを表示する。
                searchResult = dataList
            } else {
                //検索文字列を含むデータを検索結果配列に追加する。
                for data in dataList {
                    if data.containsString(testSearchBar.text!) {
                        searchResult.append(data)
                    }
                }
            }
    
            //テーブルを再読み込みする。
            testTableView.reloadData()
        }
    
    }
    
    }
    
[/code]


CC BY-SA 4.0
2020-04-06T19:24:25.790
65412
2020-04-08T13:45:28.517
2020-04-07T10:17:42.850
39481
39481
question
swift
Swift 検索機能


まず、tonyさんには、SwiftとXcodeを使って、ソフトウェア開発、プログラミングをする上で、身に付けておかなければならない知識がいくつかあります。質問に対する回答に入る前に、その必須な知識の話をさせてもらいます。

第一。プログラミング言語Swiftは、2014年に最初のバージョンがリリースされた、新しい言語です。そして2020年の今もまだ開発の途中であり、さまざまな拡張と改変を繰り返しています。拡張と改変には、細かなものも多数ありますが、ときに大規模な改変、180度方針転換した仕様変更がなされるときもありました。

`containsString(_ string: String)`

こういうメソッド名が

`contains(_ str: String)`

に変更されるということは、ざらにあることで、数年前に書かれたサンプルコードが、最新バージョンのXcodeでは、まったく通用しない、「containsString
をもっていない」ということが生じます。  
なので、初めて使うプロパティ、メソッドなどは、かならずXcode付属のドミュンメントと[リファレンス](https://developer.apple.com/documentation/foundation/nsstring/1414563-contains)にあたる必要があります。英語の勉強をする時に、初めてみる英単語は、必ず英和辞書を引いてみるのと、同じことですね。

第二。Apple製品の開発言語の標準は、Swiftですが、2014年以前それはObjective-Cでした。Objeective-
CがApple（以前のNext社の時代）の開発言語になったのが1985年のことですので、相当に古い言語といえます。が、iOSの基本フレームワーク（Foundation、UIKit）はこのObjective-
Cで記述されており、SwiftによるiOSソフトウェアの開発は、Objective-Cとの互換性の上に成り立っています。

`let dataList: [String] = []`

のプロパティ宣言にあることから、

[code]

    for data in dataList {
        if data.containsString(testSearchBar.text!) {
            searchResult.append(data)
        }
    }
    
[/code]

の箇所の変数`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](https://developer.apple.com/documentation/swift/stringprotocol/3126753-contains)

を採用するべきでしょう。  
「プロトコル」という言葉（というか概念）は、学習済みですか？もし初見だとしたら、Swift（じつはObjective-
Cにおいても同様）の言語体系の根幹をなす、重要な概念なので、すこし腰を落ち着けて、じっくり学習すべきところです。  
が、今回のご質問に即してみていくなら、プロトコルは、クラスや構造体などの型を構成する部品のようなものと、とらえる事ができます。正確ではありませんが、ひとつの面だけ見れば、そういう事ができます。  
順を追って見ていきます。まず、文字列`"あいうえお"`に、文字列`"あい"`が含まれるか、調べたいと思います。それができる関数、メソッドがないか、探します。対象が文字列ですから、`String`型のメソッドにないか、リファレンスを探します。「含まれる」という意味の英単語になっているメソッドを探します。しかし、適当な物が見つかりません。次に、`String`のリファレンスの最後にある「Conforms
To」（準拠している）に列挙してあるプロトコルをひとつひとつあたってきます。そうすると、プロトコル`StringProtocol`に、メソッド`func
contains<T>(_ other: T) -> Bool where T :
StringProtocol`というのが見つかりました。どうやらこれが使えそうです。構造体、クラスにないメソッドでも、準拠しているプロトコルにあるメソッドなら、その構造体でも、そのメソッドが使えるのです。

[code]

    let aiueo = "あいうえお"
    if aiueo.contains("あい") {
        print("Contains")
    }
    
[/code]

このような流れで、目的のメソッド、あるいはプロパティなどを見つけていくのです。

* * *

質問からは離れますが、一点だけ指摘しなければいけないところがあります。

`let dataList: [String] = []`

このようにプロパティを`let`で宣言してしまうと、要素数0の配列として固定されてしまい、なにをどうやっても要素数0から変更ができません。`let`と`var`の違いを、しっかり学習する必要があります。


CC BY-SA 4.0
2020-04-07T12:15:25.693
65443
2020-04-08T13:45:28.517
2020-04-08T13:45:28.517
18540
18540
65412
answer