---
title: Swift の可変値と不変値 〜 前回の続き（おまけ）〜 #cocoa_kansai
tags:  #cocoa関西 #swift #objective-c  
author: [熊谷友宏](https://www.docswell.com/user/es_kumagai)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/VJNGZL9978.jpg?width=480
description: 今回はちょっととりとめのないおまけのお話です。  第 60 回 Cocoa 勉強会関西で発表した内容について、いろいろ教えて頂いて、それを受けて考えていたら思いがけない発見があったりとかして、そんな風にして見えてきた事柄をややまとまりなく綴ってみました。  2015/04/11 当時に見つけた Swift 1.2 までのお話です。当時は Swift 2.0 については影も形もありませんでした。  ※ Docswell での公開に移行する直前の Slideshare での閲覧数は 1,719 でした。
published: June 15, 15
canonical: https://www.docswell.com/s/es_kumagai/K1R2M3-cocoakansaiswift-150615100520-lva1-app6892
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/VJNGZL9978.jpg)

Swift  カジュアルプログラミング
《基礎》不不変値と可変値
〜～  前回の続き（おまけ）〜～
EZ-‐‑‒NET  熊⾕谷友宏    
http://ez-‐‑‒net.jp/
2015.04.11  
@  第61回  Cocoa  勉強会関⻄西


# Page. 2

![Page Image](https://bcdn.docswell.com/page/YE9WZ423E3.jpg)

熊谷友宏
http://ez-net.jp/
@es̲kumagai
Xcode 5 徹底解説
IP Phone
音でダイヤル 音で再配達ゴッド
いつもの電卓
for iPhone
いつもの電卓
for iPad
音で再配達


# Page. 3

![Page Image](https://bcdn.docswell.com/page/GE8N1Q5L7D.jpg)

熊谷友宏
http://ez-net.jp/
@es̲kumagai
開催中
#yidev
横浜 iPhone 開発者勉強会


# Page. 4

![Page Image](https://bcdn.docswell.com/page/LELPQXYQ7R.jpg)

前回
不変値と可変値
Swift にある変数のお話


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4JM41LDK7W.jpg)

今回
前回に頂いた質問から見えた
いろいろな事柄


# Page. 6

![Page Image](https://bcdn.docswell.com/page/PJRWLK4679.jpg)

前回の内容
▶ 不変値変数と可変値変数
▶ 変数は常にコピー
▶ 値に特化した構造体


# Page. 7

![Page Image](https://bcdn.docswell.com/page/PEXPWL2D7X.jpg)

まずは訂正


# Page. 8

![Page Image](https://bcdn.docswell.com/page/3EKDVLMDJD.jpg)

訂正
構造体
変数に特化したオブジェクト


# Page. 9

![Page Image](https://bcdn.docswell.com/page/L73RM3YPJ5.jpg)

訂正
構造体
▶ データ型？
▶ オブジェクトとは言わない？


# Page. 10

![Page Image](https://bcdn.docswell.com/page/87DY64537G.jpg)

訂正
オブジェクト
▶ オブジェクト指向で
手続きの対象を抽象化する概念
▶ クラス型のインスタンス
▶ Swift では AnyObject で表現


# Page. 11

![Page Image](https://bcdn.docswell.com/page/VJP6YMGPE8.jpg)

訂正
型 Type
実体 Instance
クラス型
クラス
オブジェクト
データ型
構造体
データ


# Page. 12

![Page Image](https://bcdn.docswell.com/page/2EV3G96V7Q.jpg)

整理すると
▶ 型は設計図
- class は クラス型 を設計するもの
- struct は データ型 を設計するもの
▶ 型からインスタンスを作る
- クラス型から オブジェクト ができる
- データ型から データ ができる
▶ データを 値 や 状態 として使う


# Page. 13

![Page Image](https://bcdn.docswell.com/page/57G38ZN1JL.jpg)

AnyObject


# Page. 14

![Page Image](https://bcdn.docswell.com/page/4EQ59LQNJP.jpg)

AnyObject
▶ プロトコルのひとつ
▶ 全てのクラスが暗黙的に準拠
▶ 明示的には準拠させられない


# Page. 15

![Page Image](https://bcdn.docswell.com/page/KJ49XDN371.jpg)

AnyObject
該当するもの
// クラス
let obj:AnyObject = MyClass()


# Page. 16

![Page Image](https://bcdn.docswell.com/page/LE1KNZ5ZJG.jpg)

AnyObject
該当しないもの
// 構造体
let obj:AnyObject = MyStruct()
// 整数（構造体）
let obj:AnyObject = Int(10)
// 文字列（構造体）
let obj:AnyObject = String(&quot;STR&quot;)
// 列挙型
let obj:AnyObject = MyEnum.A


# Page. 17

![Page Image](https://bcdn.docswell.com/page/GEWD4956J2.jpg)

AnyObject
該当しないもの
// 関数
let obj:AnyObject = reduce
// クロージャー
let obj:AnyObject = { $0 + $1 }


# Page. 18

![Page Image](https://bcdn.docswell.com/page/47ZG29NRE3.jpg)

AnyObject
該当するもの
// クラスの型
let obj:AnyObject = MyClass.self
該当しないもの
// 構造体の型
let obj:AnyObject = MyStruct.self


# Page. 19

![Page Image](https://bcdn.docswell.com/page/YJ6YVK817V.jpg)

AnyObject
意味
オブジェクトの概念を持っているもの
対象
▶ MyClass
（クラスの実体）
▶ MyClass.Type （クラスの型）


# Page. 20

![Page Image](https://bcdn.docswell.com/page/GJ5GDP9LJ4.jpg)

AnyObject
ところが
プロジェクト内のどこかで
Foundation をインポートすると…


# Page. 21

![Page Image](https://bcdn.docswell.com/page/9E2Y8623ER.jpg)

AnyObject
該当するものが変化
// 構造体
let obj:AnyObject = MyStruct()
// 整数（構造体）
let obj:AnyObject = Int(10)
// 文字列（構造体）
let obj:AnyObject = String(&quot;STR&quot;)
// 列挙型
let obj:AnyObject = MyEnum.A


# Page. 22

![Page Image](https://bcdn.docswell.com/page/D7YG69Y87M.jpg)

AnyObject
なぜ Int や String などの 構造体 が
AnyObject になるのか


# Page. 23

![Page Image](https://bcdn.docswell.com/page/VENGZLP9J8.jpg)

AnyObject
Foundation の中に理由があるはず
でも、それを探るのは困難そう
NSString や NSNumber が怪しいのですが…


# Page. 24

![Page Image](https://bcdn.docswell.com/page/Y79WZ43373.jpg)

そういえば
前回の懇親会での一幕


# Page. 25

![Page Image](https://bcdn.docswell.com/page/G78N1QMLJD.jpg)

Objective-C Bridge
String と NSString って
どうやってブリッジしているの？


# Page. 26

![Page Image](https://bcdn.docswell.com/page/L7LPQX3QJR.jpg)

Objective-C Bridge
̲ObjectiveCBridgeable


# Page. 27

![Page Image](https://bcdn.docswell.com/page/4EM41LMKJW.jpg)

Objective-C Bridge
STEP 1/7
▶ ブリッジさせたい 構造体 を
̲ObjectiveCBridgeable に準拠
struct MyStruct:_ObjectiveCBridgeable {
}


# Page. 28

![Page Image](https://bcdn.docswell.com/page/PERWLKV6J9.jpg)

Objective-C Bridge
STEP 2/7
▶ ブリッジする対象のクラスを決定
▶ AnyObject 相当のものを指定
typealias _ObjectiveCType


# Page. 29

![Page Image](https://bcdn.docswell.com/page/P7XPWLZDJX.jpg)

Objective-C Bridge
STEP 3/7
▶ ブリッジできるかの判定を実装
▶ 自身の型がブリッジできるかを判定
static func
_isBridgedToObjectiveC() -&gt; Bool


# Page. 30

![Page Image](https://bcdn.docswell.com/page/37KDVL8DED.jpg)

Objective-C Bridge
STEP 4/7
▶ ブリッジするクラスの型を返却
▶ 必ず _ObjectiveCType.self を返却
public static func
_getObjectiveCType() -&gt; Any.Type


# Page. 31

![Page Image](https://bcdn.docswell.com/page/LJ3RM32PE5.jpg)

Objective-C Bridge
STEP 5/7
▶ ブリッジ後のインスタンスを返却
▶ 自身の情報から新インスタンスを作成
public func
_bridgeToObjectiveC() -&gt; _ObjectiveCType


# Page. 32

![Page Image](https://bcdn.docswell.com/page/8JDY64Z3JG.jpg)

Objective-C Bridge
STEP 6/7
▶ ブリッジ先から自身にブリッジする
▶ as 演算子によるキャスト動作を実装
public static func
_forceBridgeFromObjectiveC(
source: _ObjectiveCType,
inout result: MyObjCBridgeClass?
)


# Page. 33

![Page Image](https://bcdn.docswell.com/page/VEP6YMDP78.jpg)

Objective-C Bridge
STEP 7/7
▶ ブリッジ先から自身にブリッジする
▶ as? 演算子によるキャスト動作を実装
public static func
_conditionallyBridgeFromObjectiveC(
source: _ObjectiveCType,
inout result: MyObjCBridgeClass?
) -&gt; Bool


# Page. 34

![Page Image](https://bcdn.docswell.com/page/27V3G91VJQ.jpg)

Objective-C Bridge
ブリッジ可能な構造体の完成
struct MyStruct : _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSString
}
用途
let structValue = MyStruct()
let string = structValue as NSString


# Page. 35

![Page Image](https://bcdn.docswell.com/page/5JG38Z21EL.jpg)

Objective-C Bridge
Foundation の Objective-C ブリッジも
この方法で実装されているのでしょう
▶ String
▶ Int
▶ Array&lt;T&gt;
…


# Page. 36

![Page Image](https://bcdn.docswell.com/page/47Q59LPNEP.jpg)

もしかして


# Page. 37

![Page Image](https://bcdn.docswell.com/page/KE49XDY3J1.jpg)

再び AnyObject


# Page. 38

![Page Image](https://bcdn.docswell.com/page/L71KNZ6ZEG.jpg)

AnyObject
この Objective-C ブリッジと
構造体が AnyObject に変わる事象は
関係している？


# Page. 39

![Page Image](https://bcdn.docswell.com/page/G7WD49W6E2.jpg)

AnyObject
関係してました。
// 構造体
let obj:AnyObject = MyStruct()
▶ Swift 構造体が AnyObject に準拠
▶ AnyObject にブリッジできるから？


# Page. 40

![Page Image](https://bcdn.docswell.com/page/4JZG295R73.jpg)

AnyObject
まとめ
▶ AnyObject はプロトコル
▶ 全てのクラスが暗黙的に準拠する
▶ 原則、クラス以外は準拠しない
▶ AnyObject へブリッジできる
構造体は AnyObject に準拠する


# Page. 41

![Page Image](https://bcdn.docswell.com/page/YE6YVK91JV.jpg)

本題


# Page. 42

![Page Image](https://bcdn.docswell.com/page/GE5GDPNLE4.jpg)

値はコピーされる


# Page. 43

![Page Image](https://bcdn.docswell.com/page/972Y86537R.jpg)

前回
変数の特徴
▶ 代入時に内容をコピー
▶ let と var の相互乗り入れを実現
コピー
let value = state
コピー
let state = value


# Page. 44

![Page Image](https://bcdn.docswell.com/page/DJYG69K8JM.jpg)

前回
代入時に必ずしも
コピーされるとは限らないのでは？
たぶん そう思います。


# Page. 45

![Page Image](https://bcdn.docswell.com/page/V7NGZLR9E8.jpg)

コピーの最適化
たぶん 最適化してくれる


# Page. 46

![Page Image](https://bcdn.docswell.com/page/YJ9WZ4M3J3.jpg)

コピーの最適化
最適化が介入できそうな場所は…
▶ コンパイラ、プリプロセッサ
言語仕様の範疇で最適化
▶ オプティマイザー
最終的な最適化の専門フェーズ
▶ 標準ライブラリ
型の設計によるチューニング


# Page. 47

![Page Image](https://bcdn.docswell.com/page/GJ8N1QLLED.jpg)

コピーの最適化
Swift の強み
▶ 変数は原則コピー
代入時に暗黙的にコピーされる
Swift
暗黙コピー
var value:Int = source
Objective-C
明示コピー
NSMutableNumber* value = source.copy();


# Page. 48

![Page Image](https://bcdn.docswell.com/page/LJLPQXLQER.jpg)

コピーの最適化
Swift の強み
▶ 変数は原則コピー
代入時に暗黙的にコピーされる
▶ 不変値と可変値が明確
書き変わらない変数を把握できる
裁量でコピーを省きやすい言語仕様


# Page. 49

![Page Image](https://bcdn.docswell.com/page/47M41L1KEW.jpg)

コピーの最適化
オプティマイザーに期待


# Page. 50

![Page Image](https://bcdn.docswell.com/page/P7RWLKL6E9.jpg)

Array&lt;T&gt; の最適化


# Page. 51

![Page Image](https://bcdn.docswell.com/page/PJXPWLWDEX.jpg)

Array&lt;T&gt; の最適化
Array は値型（構造体）
▶ 代入時に暗黙コピー
▶ 全ての要素がコピーの対象
Swift
全要素の暗黙コピー
var values:Array&lt;Int&gt; = sources


# Page. 52

![Page Image](https://bcdn.docswell.com/page/3JKDVLVD7D.jpg)

Array&lt;T&gt; の最適化
要素が多いときの処理速度が心配
設計による最適化が図られている


# Page. 53

![Page Image](https://bcdn.docswell.com/page/LE3RM3MP75.jpg)

Array&lt;T&gt; の最適化
Array の最適化
▶ 要素をバッファーで保持
▶ 代入時はポインターのコピーで済ませる
▶ 内容の書き換え時にバッファーをコピー
内容が変わらないうちは共有する


# Page. 54

![Page Image](https://bcdn.docswell.com/page/8EDY6463EG.jpg)

Array&lt;T&gt; の最適化
コピーの動作（代入時）
コピー
配列
配列
バッファーは共有
Buﬀer


# Page. 55

![Page Image](https://bcdn.docswell.com/page/V7P6YMYPJ8.jpg)

Array&lt;T&gt; の最適化
コピーの動作（書き換え時）
書き込み！
配列
配列
×
Buﬀer
Buﬀer
遅延コピー


# Page. 56

![Page Image](https://bcdn.docswell.com/page/2JV3G9GVEQ.jpg)

Array&lt;T&gt; の最適化
原則コピーの体をなしつつ
最適化を実現
▶ 代入時や引数へ渡すときの
コピーの負荷は心配無用
▶ 内容を書き換えるときに負荷が発生


# Page. 57

![Page Image](https://bcdn.docswell.com/page/5EG38Z817L.jpg)

余談


# Page. 58

![Page Image](https://bcdn.docswell.com/page/4JQ59L9N7P.jpg)

CGImage


# Page. 59

![Page Image](https://bcdn.docswell.com/page/K749XDX3E1.jpg)

CGImage
定義
Objective-C
// 実装は隠蔽されているがＣ構造体
typedef struct CGImage *CGImageRef;
Swift
// 実装は隠蔽
typealias CGImageRef = CGImage


# Page. 60

![Page Image](https://bcdn.docswell.com/page/LJ1KNZNZ7G.jpg)

CGImage
定義
Swift
▶ AnyObject である
▶ ̲ObjectiveCBridgeable ではない
▶ Type は ̲̲NSCFType（詳細不明）
クラスを使った実装になっている様子


# Page. 61

![Page Image](https://bcdn.docswell.com/page/GJWD494672.jpg)

CGImage
Objective-C とは違った方法で
最適化が図られていそう


# Page. 62

![Page Image](https://bcdn.docswell.com/page/4EZG292RJ3.jpg)

let の遅延初期化


# Page. 63

![Page Image](https://bcdn.docswell.com/page/Y76YVKV1EV.jpg)

let の遅延初期化
概要
▶ Swift 1.2 の新機能
▶ 不変値変数の宣言と初期化を分離可能
Swift
let image:UIImage
if condition {
image = UIImage(named: &quot;maru.png&quot;)
}
else {
image = UIImage(named: &quot;batsu.png&quot;)
}


# Page. 64

![Page Image](https://bcdn.docswell.com/page/G75GDPDL74.jpg)

let の遅延初期化
欠点
▶ 宣言と初期化の分離
▶ コードを追わないと値が分からない
Swift
let image:UIImage
if condition {
image = UIImage(named: &quot;maru.png&quot;)
}
else {
image = UIImage(named: &quot;batsu.png&quot;)
}


# Page. 65

![Page Image](https://bcdn.docswell.com/page/9J2Y8683JR.jpg)

let の遅延初期化
活用できそうな場面がありました。
再帰呼び出し可能なクロージャーを
let だけで実現したい場面


# Page. 66

![Page Image](https://bcdn.docswell.com/page/DEYG6968EM.jpg)

let の遅延初期化
Swift 1.1 時代
再帰呼び出し可能なクロージャー
▶ let だけで定義すると未初期化エラー


# Page. 67

![Page Image](https://bcdn.docswell.com/page/VJNGZLZ978.jpg)

let の遅延初期化
Swift 1.1 までは
再帰呼び出し可能なクロージャーを
let だけで実現しようとすると…
➡ 不動点コンビネーター？


# Page. 68

![Page Image](https://bcdn.docswell.com/page/YE9WZ4Z3E3.jpg)

let の遅延初期化
不動点コンビネーター
f(g(f)) = g(f)
関数 f を引数に取る関数 g を
次の式を満たすように作る
…らしい


# Page. 69

![Page Image](https://bcdn.docswell.com/page/GE8N1Q1L7D.jpg)

let の遅延初期化
不動点コンビネーター
ffffff…f(g(f)) = g(f)
関数 g をいっかい嚙ますことで
本来の関数 f を g(f) で再起表現できる
…らしい


# Page. 70

![Page Image](https://bcdn.docswell.com/page/LELPQXQQ7R.jpg)

let の遅延初期化
Swift 1.1 時代
再帰呼び出し可能なクロージャー


# Page. 71

![Page Image](https://bcdn.docswell.com/page/4JM413KK7W.jpg)

let の遅延初期化
Swift 1.1 時代
再帰呼び出し可能なクロージャー


# Page. 72

![Page Image](https://bcdn.docswell.com/page/PJRWLQX679.jpg)

let の遅延初期化
再帰呼び出し可能なクロージャー
▶ var なら宣言と実装を分ければ OK
▶ ただ var の使用はできるだけ避けたい


# Page. 73

![Page Image](https://bcdn.docswell.com/page/PEXPW56D7X.jpg)

let の遅延初期化
再帰呼び出し可能なクロージャー
▶ Swift 1.2 からは let でも可能
▶ let で宣言と実装を分ければ OK


# Page. 74

![Page Image](https://bcdn.docswell.com/page/3EKDV61DJD.jpg)

おしまい。


# Page. 75

![Page Image](https://bcdn.docswell.com/page/L73RM6QPJ5.jpg)

今日の内容
構造体
▶ オブジェクトとは呼ばなかった
AnyObject
▶ 全てのクラスが暗黙的に準拠
▶ Objective-C ブリッジ可能な構造体も
値のコピー
▶ 代入時はコピー
▶ 最適化（暗黙コピー、配列型の設計）


