Swiftの文字列はどのように格納されるか？調べてみた

こんにちは。[仙台iOS開発者勉強会(SWWDC) Advent Calendar 2014](http://qiita.com/advent-calendar/2014/iosendai)の8日目の記事です。
役に立ちそうで役に立たない Swift の文字列がメモリにどのように格納されるか調べてみました。

# Swiftの文字列ってどうなってるの？
Swift は Objective-C のラッパーみたいなイメージだったので、多分 Objective-C と大体同じだろうと思ってました。とかいいながら、Objective-C 自体私はよくわからなかったりする。

# Swiftの文字列は Java と同じように格納される
結論からいうと Java と同じように、文字列はヒープに格納され、同じ文字列を定義すれば同じアドレスを参照することになる。
「Java と同じように」という曖昧な表現なのは、Java だと「String定数プール」なるものがあり、そのような仕組みが Swift や Objective-C にあるか不明だったからです。
あと、Java にはガベージコレクションがあるが、Swift や Objective-C は ARC という仕組みの違いもある。

日本語だと何を言っているかよくわからないと思うので、PlayGroundで実行したサンプルコードと結果を見て欲しい。

![swift_letvar_same_address.png](https://qiita-image-store.s3.amazonaws.com/0/31790/7562ae6a-db5d-8aaf-81d9-d5fe626888a2.png)

let と var で同じ "Hello" の文字列を宣言したが、どちらも同じアドレスを指している。ここでのポイントは `String._core._baseAddress` という非公開 Properties で確認することです。`[NSString format:]`で取得しようとしたところ、次のように毎回違うアドレスを取得してしまいハマりました。

![swift_letvar_format.png](https://qiita-image-store.s3.amazonaws.com/0/31790/ed56e965-cd68-98e2-0921-86db39bc2f68.png)

## 文字列を結合すると別なアドレスを確保する
次に文字列を結合した例を見てください。最初のサンプルコードの後に letstr と varstr を結合させてみました。letstrのアドレスは変わりませんが、文字列結合後のvarstrのアドレスは変わりました。

![swift_letvar_con.png](https://qiita-image-store.s3.amazonaws.com/0/31790/f57cb8ad-dba3-ef7b-ca10-e8a2010151c1.png)

# Swift の String は値型である！ 
これはあまり自信がないのですが、リファレンスにはこう書いてあります。強調表示は筆者が編集しました。

> Strings Are Value Types
**Swift’s String type is a value type.** If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. 
（後略）

なんと、Swift の String は値型(value type)であるとのこと。なので、単純にformatで表示した場合は毎回違うアドレスになっていたんですね。けれども、裏ではちゃんと同じアドレスで格納している。小賢しいですね。Swift は Objective-C の単なるラッパーだと思っていたらそうではなさそうです。

このような仕組みは [Copy-on-write](http://en.wikipedia.org/wiki/Copy-on-write) と呼ばれるそうですが、私にはよくわからなかったです。Arrayについて、 @koher さんが[SwiftにおいてCopy-on-Writeは問題にならないと思う - Qiita](http://qiita.com/koher/items/8c22e010ad484d2cd321)でまとめてくださっているので、参考にしてみてください。

# 結論：で、何が嬉しいの？
最初に述べたとおり役に立ちそうな情報ですが、おそらく大半の人にとっては役に立たないと思います。
パフォーマンスチューニングでこんなところ気にしても、数ナノ秒しか縮まらないと思いますので、DBなりネットワークで数ミリ秒縮める努力をすべきかなぁと思います。

私にとって収穫だったのは、String._coreという隠しプロパティが発見できたことですかねぇ。あ、でもアプリの審査時には消さないとダメですよ。リファレンスにない隠しプロパティの使用は100％リジェクトされるでしょうから。

# SWWDCについて
元々、SWWDCのメンバーである @ktanaka117 氏のひょんな質問からこの記事のネタができました。
どこをどう略すと SWWDC になるとかは置いておいて、実際に仕事でアプリを作っている人たちが集まってるので、ペーパー開発者（アプリをリリースしたこと無い）な自分にとっては大変刺激的で、個人的に好きな勉強会の一つです。

あとはみんなモバイルサービスを使ってアプリを作ってくれれば僕からいうことは何もありません。

毎月一回は勉強会やってるようなので、興味のある方は [IOSendai 開発者グループ](https://www.facebook.com/groups/157172724446381/) にご参加ください。

# 参考リンク
[Java - Stringクラス](http://www.booran.com/menu/java/stringclass.html)
[Effective Objective-C 2.0について簡単に - けーろぐ](http://keeetaka.hateblo.jp/entry/2014/05/25/012732)
[Printing a variable memory address in swift - Stack Overflow](http://stackoverflow.com/questions/24058906/printing-a-variable-memory-address-in-swift)
[The Swift Programming Language: Strings and Characters](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html)
[SwiftにおいてCopy-on-Writeは問題にならないと思う - Qiita](http://qiita.com/koher/items/8c22e010ad484d2cd321)