Swift4におけるsubstringについて

今回はsubstringの話です。これまた、iOS11対応をしている際に出てきた話で、xcodeを9にアップデートしswiftを4にマイグレーションした時に、文字列のsubstringでdeprecatedのワーニングが出たので、それを消すための対処方法を紹介致します


 

Swift3までの書き方でワーニング

Swift4では、Swift3までのsubstringの書き方をしていると、以下のようなワーニングが表示されるようになりました。以下の例はsubstring(to:)です
Swiftと言うと、substringが非常に使いづらかった(indexの扱いが・・・)ので、何かが変わった(改善された?)ようですね。

'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range upto' operator.

substring(to:)における書き換え例

例えば、文字列の最後の1文字を削除するようなsubstringを例に、ワーニングが消えるように書き換えたいと思います。”hoge!” -> “hoge” にします

let index = "hoge!".index("hoge!".endIndex, offsetBy: -1)

// Swift3
let a = "hoge!".substring(to: index)
print(a) // -> "hoge"

// Swift4
let b = "hoge!"[..<index]
print(b) // -> "hoge"

これを見ると、単純にシンタックスシュガー的なノリで書く量を減らした書き方だけが有効になった感じでしょうか? 前から書けましたっけ?
個人的には上の書き方でのほうがわかりやすい気がしないでもないですが。。。 どちらかと言うとindexの使い方のほうが、明らかに面倒くさいしわかりにくいですね。ポリシーはあるんでしょうが、単純にIntが使えるとありがたいですね

戻り値

実は上記の2つの書き方で戻り値の型が違います。substringの戻り値の型はString、[]の場合はString.SubSequenceが返ってきます。型の違いでエラーになる場合は、Stringで作り直してあげる必要があります

  • 以下のようなエラーが出た場合は・・・
Cannot convert value of type 'String.SubSequence' (aka 'Substring') to expected argument type 'String'
Cannot convert return expression of type 'Character' to return type 'String'
Cannot subscript a value of type 'String'
Cannot assign value of type 'String.SubSequence' (aka 'Substring') to type 'String'
  • 以下のような感じで作り直します
let hoge = String("hoge!"[..<index])

to以外の例

  • substring(from:)の場合
'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.
let index = "!hoge".index(after: "!hoge".startIndex)

// Swift3
let a = "!hoge".substring(from: index)
print(a) // -> "hoge"

// Swift4
let b = "!hoge"[index...]
print(b) // -> "hoge"
  • substring(with:)の場合
'substring(with:)' is deprecated: Please use String slicing subscript.
let hoge = "!hoge!"
let start = hoge.index(hoge.startIndex, offsetBy: 1)
let end = hoge.index(hoge.endIndex, offsetBy: -1)

// Swift3
let a = hoge.substring(with: Range(start..<end))
print(a) // -> "hoge"

// Swift4
let b = hoge[start..<end]
print(b) // -> "hoge"

結局のところ

substringの範囲の指定方法としては、以下の5種類ぐらいあるのでしょうかね。
この表現はfor文なんかでも使えるみたいですね(上2つのみ)。どうして「〜より大きい」の表現は存在しないのでしょうか。不思議

let hoge = "!hoge!!"
let start = hoge.index(hoge.startIndex, offsetBy: 1)
let end = hoge.index(hoge.endIndex, offsetBy: -2)

// start以上、end以下
print(hoge[start...end]) // -> hoge!
// start以上、endより小さい
print(hoge[start..<end]) // -> hoge
// start以上
print(hoge[start...]) // -> hoge!!
// end以下
print(hoge[...end]) // -> !hoge!
// endより小さい
print(hoge[..<end]) // -> !hoge

for文の範囲(Range)指定は以下の感じになります。

(0...5).forEach { (i) in
    print(i)
}
// 0
// 1
// 2
// 3
// 4
// 5

for i in 0...5 {
    print(i)
}
// 0
// 1
// 2
// 3
// 4
// 5

(0..<5).forEach { (i) in
    print(i)
}
// 0
// 1
// 2
// 3
// 4

for i in 0..<5 {
    print(i)
}
// 0
// 1
// 2
// 3
// 4

参考サイト

以下のサイトを参考にさせて頂きました。
Basic Operators

関連記事

【Swift4】「'characters' is deprecated」というワ...

【Swift】UIViewControllerでStatic CellsのTab...

【Ubuntu】UnuntuにSwiftをインストールしてみた件

【Ubuntu】Ubuntuを18.04LTSにアップグレードしてみた

iPhoneのスクリーンサイズ一覧

【Xcode】ショートカット集