Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
EZ-‐‑‒NET  熊⾕谷友宏    
http://ez-‐‑‒net.jp/
2015.04.11  
@  第61回  Cocoa  勉強会関⻄西
Swift  カジュアルプログラミング
《基礎》不不変値と可変値
〜~  前回の続き(お...
熊谷友宏
http://ez-net.jp/
@es_kumagai
Xcode 5 徹底解説
IP Phone 音でダイヤル 音で再配達ゴッド
いつもの電卓
for iPhone
いつもの電卓
for iPad
音で再配達
熊谷友宏
http://ez-net.jp/
@es_kumagai
#yidev
横浜 iPhone 開発者勉強会
開催中
不変値と可変値
前回
Swift にある変数のお話
前回に頂いた質問から見えた
今回
いろいろな事柄
前回の内容
▶ 不変値変数と可変値変数
▶ 変数は常にコピー
▶ 値に特化した構造体
まずは訂正
構造体
変数に特化したオブジェクト
訂正
▶ データ型?
▶ オブジェクトとは言わない?
訂正
構造体
▶ オブジェクト指向で

手続きの対象を抽象化する概念
▶ クラス型のインスタンス
▶ Swift では AnyObject で表現
訂正
オブジェクト
訂正
クラス
構造体
データ型
クラス型
オブジェクト
データ
型 Type 実体 Instance
▶ 型は設計図

- class は クラス型 を設計するもの

- struct は データ型 を設計するもの
▶ 型からインスタンスを作る

- クラス型から オブジェクト ができる

- データ型から データ ができる
▶ データを 値 ...
AnyObject
AnyObject
▶ プロトコルのひとつ
▶ 全てのクラスが暗黙的に準拠
▶ 明示的には準拠させられない
AnyObject
該当するもの
// クラス
let obj:AnyObject = MyClass()
該当しないもの
// 構造体
let obj:AnyObject = MyStruct()
// 整数(構造体)
let obj:AnyObject = Int(10)
// 文字列(構造体)
let obj:AnyObject = Strin...
該当しないもの
// 関数
let obj:AnyObject = reduce
// クロージャー
let obj:AnyObject = { $0 + $1 }
AnyObject
該当するもの
該当しないもの
// クラスの型
let obj:AnyObject = MyClass.self
AnyObject
// 構造体の型
let obj:AnyObject = MyStruct.self
AnyObject
意味
オブジェクトの概念を持っているもの
対象
▶ MyClass
▶ MyClass.Type
(クラスの実体)
(クラスの型)
プロジェクト内のどこかで
AnyObject
Foundation をインポートすると…
ところが
該当するものが変化
// 構造体
let obj:AnyObject = MyStruct()
// 整数(構造体)
let obj:AnyObject = Int(10)
// 文字列(構造体)
let obj:AnyObject = Str...
なぜ Int や String などの 構造体 が
AnyObject になるのか
AnyObject
Foundation の中に理由があるはず
でも、それを探るのは困難そう
AnyObject
NSString や NSNumber が怪しいのですが…
前回の懇親会での一幕
そういえば
Objective-C Bridge
String と NSString って
どうやってブリッジしているの?
Objective-C Bridge
_ObjectiveCBridgeable
STEP 1/7
Objective-C Bridge
struct MyStruct:_ObjectiveCBridgeable {
}
▶ ブリッジさせたい 構造体 を

_ObjectiveCBridgeable に準拠
STEP 2/7
Objective-C Bridge
typealias _ObjectiveCType
▶ ブリッジする対象のクラスを決定
▶ AnyObject 相当のものを指定
STEP 3/7
Objective-C Bridge
static func
_isBridgedToObjectiveC() -> Bool
▶ ブリッジできるかの判定を実装
▶ 自身の型がブリッジできるかを判定
STEP 4/7
Objective-C Bridge
public static func
_getObjectiveCType() -> Any.Type
▶ ブリッジするクラスの型を返却
▶ 必ず _ObjectiveCType.self...
STEP 5/7
Objective-C Bridge
public func
_bridgeToObjectiveC() -> _ObjectiveCType
▶ ブリッジ後のインスタンスを返却
▶ 自身の情報から新インスタンスを作成
STEP 6/7
Objective-C Bridge
public static func
_forceBridgeFromObjectiveC(
source: _ObjectiveCType,
inout result: MyObjCBr...
STEP 7/7
Objective-C Bridge
public static func
_conditionallyBridgeFromObjectiveC(
source: _ObjectiveCType,
inout result: ...
ブリッジ可能な構造体の完成
用途
Objective-C Bridge
struct MyStruct : _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSString
}
let s...
Foundation の Objective-C ブリッジも
Objective-C Bridge
この方法で実装されているのでしょう
▶ String
▶ Int
▶ Array<T>

…
もしかして
再び AnyObject
この Objective-C ブリッジと
構造体が AnyObject に変わる事象は
AnyObject
関係している?
AnyObject
関係してました。
// 構造体
let obj:AnyObject = MyStruct()
▶ Swift 構造体が AnyObject に準拠
▶ AnyObject にブリッジできるから?
AnyObject
まとめ
▶ AnyObject はプロトコル
▶ 全てのクラスが暗黙的に準拠する
▶ 原則、クラス以外は準拠しない
▶ AnyObject へブリッジできる

構造体は AnyObject に準拠する
本題
値はコピーされる
前回
変数の特徴
▶ 代入時に内容をコピー
▶ let と var の相互乗り入れを実現
let value = state
let state = value
コピー
コピー
前回
代入時に必ずしも
コピーされるとは限らないのでは?
たぶん そう思います。
コピーの最適化
たぶん 最適化してくれる
最適化が介入できそうな場所は…
▶ コンパイラ、プリプロセッサ

言語仕様の範疇で最適化
▶ オプティマイザー

最終的な最適化の専門フェーズ
▶ 標準ライブラリ

型の設計によるチューニング
コピーの最適化
Swift の強み
▶ 変数は原則コピー

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

代入時に暗黙的にコピーされる
▶ 不変値と可変値が明確

書き変わらない変数を把握できる
裁量でコピーを省きやすい言語仕様
コピーの最適化
オプティマイザーに期待
コピーの最適化
Array<T> の最適化
Arrayは値型(構造体)
▶ 代入時に暗黙コピー
▶ 全ての要素がコピーの対象
Array<T> の最適化
var values:Array<Int> = sources
Swift 全要素の暗黙コピー
Array<T> の最適化
要素が多いときの処理速度が心配
設計による最適化が図られている
Arrayの最適化
▶ 要素をバッファーで保持
▶ 代入時はポインターのコピーで済ませる
▶ 内容の書き換え時にバッファーをコピー
Array<T> の最適化
内容が変わらないうちは共有する
コピーの動作(代入時)
Array<T> の最適化
配列
Buffer
コピー
配列
バッファーは共有
コピーの動作(書き換え時)
Array<T> の最適化
配列
Buffer
配列配列
Buffer Buffer
×
遅延コピー
書き込み!
Array<T> の最適化
原則コピーの体をなしつつ
最適化を実現
▶ 代入時や引数へ渡すときの

コピーの負荷は心配無用
▶ 内容を書き換えるときに負荷が発生
余談
CGImage
Objective-C
定義
CGImage
Swift
// 実装は隠蔽されているがC構造体
typedef struct CGImage *CGImageRef;
// 実装は隠蔽
typealias CGImageRef = CGImage
Swift
定義
CGImage
▶ AnyObject である
▶ _ObjectiveCBridgeable ではない
▶ Type は __NSCFType(詳細不明)
クラスを使った実装になっている様子
Objective-C とは違った方法で
最適化が図られていそう
CGImage
let の遅延初期化
Swift
概要
let の遅延初期化
▶ Swift 1.2 の新機能
▶ 不変値変数の宣言と初期化を分離可能
let image:UIImage
if condition {
image = UIImage(named: "maru.png...
欠点
let の遅延初期化
▶ 宣言と初期化の分離
▶ コードを追わないと値が分からない
Swift
let image:UIImage
if condition {
image = UIImage(named: "maru.png")
}
e...
活用できそうな場面がありました。
再帰呼び出し可能なクロージャーを

let だけで実現したい場面
let の遅延初期化
再帰呼び出し可能なクロージャー
let の遅延初期化
▶ let だけで定義すると未初期化エラー
Swift 1.1 時代
let の遅延初期化
let だけで実現しようとすると…
再帰呼び出し可能なクロージャーを
Swift 1.1 までは
➡ 不動点コンビネーター?
let の遅延初期化
次の式を満たすように作る
関数 f を引数に取る関数 g を
不動点コンビネーター
f(g(f)) = g(f)
…らしい
let の遅延初期化
本来の関数 f を g(f) で再起表現できる
関数 g をいっかい嚙ますことで
不動点コンビネーター
ffffff…f(g(f)) = g(f)
…らしい
再帰呼び出し可能なクロージャー
let の遅延初期化
Swift 1.1 時代
再帰呼び出し可能なクロージャー
let の遅延初期化
Swift 1.1 時代
再帰呼び出し可能なクロージャー
let の遅延初期化
▶ var なら宣言と実装を分ければ OK
▶ ただ var の使用はできるだけ避けたい
再帰呼び出し可能なクロージャー
let の遅延初期化
▶ Swift 1.2 からは let でも可能
▶ let で宣言と実装を分ければ OK
おしまい。
構造体
▶ オブジェクトとは呼ばなかった
AnyObject
▶ 全てのクラスが暗黙的に準拠
▶ Objective-C ブリッジ可能な構造体も
値のコピー
▶ 代入時はコピー
▶ 最適化(暗黙コピー、配列型の設計)
今日の内容
Upcoming SlideShare
Loading in …5
×

Swift の可変値と不変値 〜 前回の続き(おまけ)〜 #cocoa_kansai

今回はちょっととりとめのないおまけのお話です。

第 60 回 Cocoa 勉強会関西で発表した内容について、いろいろ教えて頂いて、それを受けて考えていたら思いがけない発見があったりとかして、そんな風にして見えてきた事柄をややまとまりなく綴ってみました。

2015/04/11 当時に見つけた Swift 1.2 までのお話です。当時は Swift 2.0 については影も形もありませんでした。

  • Login to see the comments

Swift の可変値と不変値 〜 前回の続き(おまけ)〜 #cocoa_kansai

  1. 1. EZ-‐‑‒NET  熊⾕谷友宏     http://ez-‐‑‒net.jp/ 2015.04.11   @  第61回  Cocoa  勉強会関⻄西 Swift  カジュアルプログラミング 《基礎》不不変値と可変値 〜~  前回の続き(おまけ)〜~
  2. 2. 熊谷友宏 http://ez-net.jp/ @es_kumagai Xcode 5 徹底解説 IP Phone 音でダイヤル 音で再配達ゴッド いつもの電卓 for iPhone いつもの電卓 for iPad 音で再配達
  3. 3. 熊谷友宏 http://ez-net.jp/ @es_kumagai #yidev 横浜 iPhone 開発者勉強会 開催中
  4. 4. 不変値と可変値 前回 Swift にある変数のお話
  5. 5. 前回に頂いた質問から見えた 今回 いろいろな事柄
  6. 6. 前回の内容 ▶ 不変値変数と可変値変数 ▶ 変数は常にコピー ▶ 値に特化した構造体
  7. 7. まずは訂正
  8. 8. 構造体 変数に特化したオブジェクト 訂正
  9. 9. ▶ データ型? ▶ オブジェクトとは言わない? 訂正 構造体
  10. 10. ▶ オブジェクト指向で
 手続きの対象を抽象化する概念 ▶ クラス型のインスタンス ▶ Swift では AnyObject で表現 訂正 オブジェクト
  11. 11. 訂正 クラス 構造体 データ型 クラス型 オブジェクト データ 型 Type 実体 Instance
  12. 12. ▶ 型は設計図
 - class は クラス型 を設計するもの
 - struct は データ型 を設計するもの ▶ 型からインスタンスを作る
 - クラス型から オブジェクト ができる
 - データ型から データ ができる ▶ データを 値 や 状態 として使う 整理すると
  13. 13. AnyObject
  14. 14. AnyObject ▶ プロトコルのひとつ ▶ 全てのクラスが暗黙的に準拠 ▶ 明示的には準拠させられない
  15. 15. AnyObject 該当するもの // クラス let obj:AnyObject = MyClass()
  16. 16. 該当しないもの // 構造体 let obj:AnyObject = MyStruct() // 整数(構造体) let obj:AnyObject = Int(10) // 文字列(構造体) let obj:AnyObject = String("STR") // 列挙型 let obj:AnyObject = MyEnum.A AnyObject
  17. 17. 該当しないもの // 関数 let obj:AnyObject = reduce // クロージャー let obj:AnyObject = { $0 + $1 } AnyObject
  18. 18. 該当するもの 該当しないもの // クラスの型 let obj:AnyObject = MyClass.self AnyObject // 構造体の型 let obj:AnyObject = MyStruct.self
  19. 19. AnyObject 意味 オブジェクトの概念を持っているもの 対象 ▶ MyClass ▶ MyClass.Type (クラスの実体) (クラスの型)
  20. 20. プロジェクト内のどこかで AnyObject Foundation をインポートすると… ところが
  21. 21. 該当するものが変化 // 構造体 let obj:AnyObject = MyStruct() // 整数(構造体) let obj:AnyObject = Int(10) // 文字列(構造体) let obj:AnyObject = String("STR") // 列挙型 let obj:AnyObject = MyEnum.A AnyObject
  22. 22. なぜ Int や String などの 構造体 が AnyObject になるのか AnyObject
  23. 23. Foundation の中に理由があるはず でも、それを探るのは困難そう AnyObject NSString や NSNumber が怪しいのですが…
  24. 24. 前回の懇親会での一幕 そういえば
  25. 25. Objective-C Bridge String と NSString って どうやってブリッジしているの?
  26. 26. Objective-C Bridge _ObjectiveCBridgeable
  27. 27. STEP 1/7 Objective-C Bridge struct MyStruct:_ObjectiveCBridgeable { } ▶ ブリッジさせたい 構造体 を
 _ObjectiveCBridgeable に準拠
  28. 28. STEP 2/7 Objective-C Bridge typealias _ObjectiveCType ▶ ブリッジする対象のクラスを決定 ▶ AnyObject 相当のものを指定
  29. 29. STEP 3/7 Objective-C Bridge static func _isBridgedToObjectiveC() -> Bool ▶ ブリッジできるかの判定を実装 ▶ 自身の型がブリッジできるかを判定
  30. 30. STEP 4/7 Objective-C Bridge public static func _getObjectiveCType() -> Any.Type ▶ ブリッジするクラスの型を返却 ▶ 必ず _ObjectiveCType.self を返却
  31. 31. STEP 5/7 Objective-C Bridge public func _bridgeToObjectiveC() -> _ObjectiveCType ▶ ブリッジ後のインスタンスを返却 ▶ 自身の情報から新インスタンスを作成
  32. 32. STEP 6/7 Objective-C Bridge public static func _forceBridgeFromObjectiveC( source: _ObjectiveCType, inout result: MyObjCBridgeClass? ) ▶ ブリッジ先から自身にブリッジする ▶ as 演算子によるキャスト動作を実装
  33. 33. STEP 7/7 Objective-C Bridge public static func _conditionallyBridgeFromObjectiveC( source: _ObjectiveCType, inout result: MyObjCBridgeClass? ) -> Bool ▶ ブリッジ先から自身にブリッジする ▶ as? 演算子によるキャスト動作を実装
  34. 34. ブリッジ可能な構造体の完成 用途 Objective-C Bridge struct MyStruct : _ObjectiveCBridgeable { typealias _ObjectiveCType = NSString } let structValue = MyStruct() let string = structValue as NSString
  35. 35. Foundation の Objective-C ブリッジも Objective-C Bridge この方法で実装されているのでしょう ▶ String ▶ Int ▶ Array<T>
 …
  36. 36. もしかして
  37. 37. 再び AnyObject
  38. 38. この Objective-C ブリッジと 構造体が AnyObject に変わる事象は AnyObject 関係している?
  39. 39. AnyObject 関係してました。 // 構造体 let obj:AnyObject = MyStruct() ▶ Swift 構造体が AnyObject に準拠 ▶ AnyObject にブリッジできるから?
  40. 40. AnyObject まとめ ▶ AnyObject はプロトコル ▶ 全てのクラスが暗黙的に準拠する ▶ 原則、クラス以外は準拠しない ▶ AnyObject へブリッジできる
 構造体は AnyObject に準拠する
  41. 41. 本題
  42. 42. 値はコピーされる
  43. 43. 前回 変数の特徴 ▶ 代入時に内容をコピー ▶ let と var の相互乗り入れを実現 let value = state let state = value コピー コピー
  44. 44. 前回 代入時に必ずしも コピーされるとは限らないのでは? たぶん そう思います。
  45. 45. コピーの最適化 たぶん 最適化してくれる
  46. 46. 最適化が介入できそうな場所は… ▶ コンパイラ、プリプロセッサ
 言語仕様の範疇で最適化 ▶ オプティマイザー
 最終的な最適化の専門フェーズ ▶ 標準ライブラリ
 型の設計によるチューニング コピーの最適化
  47. 47. Swift の強み ▶ 変数は原則コピー
 代入時に暗黙的にコピーされる コピーの最適化 var value:Int = source Swift NSMutableNumber* value = source.copy(); Objective-C 明示コピー 暗黙コピー
  48. 48. Swift の強み ▶ 変数は原則コピー
 代入時に暗黙的にコピーされる ▶ 不変値と可変値が明確
 書き変わらない変数を把握できる 裁量でコピーを省きやすい言語仕様 コピーの最適化
  49. 49. オプティマイザーに期待 コピーの最適化
  50. 50. Array<T> の最適化
  51. 51. Arrayは値型(構造体) ▶ 代入時に暗黙コピー ▶ 全ての要素がコピーの対象 Array<T> の最適化 var values:Array<Int> = sources Swift 全要素の暗黙コピー
  52. 52. Array<T> の最適化 要素が多いときの処理速度が心配 設計による最適化が図られている
  53. 53. Arrayの最適化 ▶ 要素をバッファーで保持 ▶ 代入時はポインターのコピーで済ませる ▶ 内容の書き換え時にバッファーをコピー Array<T> の最適化 内容が変わらないうちは共有する
  54. 54. コピーの動作(代入時) Array<T> の最適化 配列 Buffer コピー 配列 バッファーは共有
  55. 55. コピーの動作(書き換え時) Array<T> の最適化 配列 Buffer 配列配列 Buffer Buffer × 遅延コピー 書き込み!
  56. 56. Array<T> の最適化 原則コピーの体をなしつつ 最適化を実現 ▶ 代入時や引数へ渡すときの
 コピーの負荷は心配無用 ▶ 内容を書き換えるときに負荷が発生
  57. 57. 余談
  58. 58. CGImage
  59. 59. Objective-C 定義 CGImage Swift // 実装は隠蔽されているがC構造体 typedef struct CGImage *CGImageRef; // 実装は隠蔽 typealias CGImageRef = CGImage
  60. 60. Swift 定義 CGImage ▶ AnyObject である ▶ _ObjectiveCBridgeable ではない ▶ Type は __NSCFType(詳細不明) クラスを使った実装になっている様子
  61. 61. Objective-C とは違った方法で 最適化が図られていそう CGImage
  62. 62. let の遅延初期化
  63. 63. Swift 概要 let の遅延初期化 ▶ Swift 1.2 の新機能 ▶ 不変値変数の宣言と初期化を分離可能 let image:UIImage if condition { image = UIImage(named: "maru.png") } else { image = UIImage(named: "batsu.png") }
  64. 64. 欠点 let の遅延初期化 ▶ 宣言と初期化の分離 ▶ コードを追わないと値が分からない Swift let image:UIImage if condition { image = UIImage(named: "maru.png") } else { image = UIImage(named: "batsu.png") }
  65. 65. 活用できそうな場面がありました。 再帰呼び出し可能なクロージャーを
 let だけで実現したい場面 let の遅延初期化
  66. 66. 再帰呼び出し可能なクロージャー let の遅延初期化 ▶ let だけで定義すると未初期化エラー Swift 1.1 時代
  67. 67. let の遅延初期化 let だけで実現しようとすると… 再帰呼び出し可能なクロージャーを Swift 1.1 までは ➡ 不動点コンビネーター?
  68. 68. let の遅延初期化 次の式を満たすように作る 関数 f を引数に取る関数 g を 不動点コンビネーター f(g(f)) = g(f) …らしい
  69. 69. let の遅延初期化 本来の関数 f を g(f) で再起表現できる 関数 g をいっかい嚙ますことで 不動点コンビネーター ffffff…f(g(f)) = g(f) …らしい
  70. 70. 再帰呼び出し可能なクロージャー let の遅延初期化 Swift 1.1 時代
  71. 71. 再帰呼び出し可能なクロージャー let の遅延初期化 Swift 1.1 時代
  72. 72. 再帰呼び出し可能なクロージャー let の遅延初期化 ▶ var なら宣言と実装を分ければ OK ▶ ただ var の使用はできるだけ避けたい
  73. 73. 再帰呼び出し可能なクロージャー let の遅延初期化 ▶ Swift 1.2 からは let でも可能 ▶ let で宣言と実装を分ければ OK
  74. 74. おしまい。
  75. 75. 構造体 ▶ オブジェクトとは呼ばなかった AnyObject ▶ 全てのクラスが暗黙的に準拠 ▶ Objective-C ブリッジ可能な構造体も 値のコピー ▶ 代入時はコピー ▶ 最適化(暗黙コピー、配列型の設計) 今日の内容

×