UIViewのメソッドにCGContextRefオブジェクトを渡してStoryBoard上に図形を描画する
内容
iPhone/iPadプログラミングバイブル iOS9/Xcode7/Swift 対応 (smart phone programming bible)
- 作者: 布留川英一
- 出版社/メーカー: ソシム
- 発売日: 2015/10/27
- メディア: 単行本
- この商品を含むブログ (1件) を見る
上の本を参考にiOSのUIViewと戯れています。
- 図形の描画
- 色や太さなどの設定と描画にCGContextRefを使う
- 直線の描画
- 円の描画
- 塗りつぶしについて
タッチイベントの処理、タイマー処理までやったけど、それは一旦寝て起きてからまとめます。
図形の描画
色や太さなどの設定と描画にCGContextRefを使う CGContextRefのオブジェクトを使います。
色とか透明度とか太さとかいろいろもって描画の設定を持ったクラスの名前をContextとして~みたいな話を読んでから、AndroidのContextよりダイレクトにそういう事例に見えるクラスが来た~という感じです*1。
基本的に、CGContextRefのオブジェクトをUIViewのインスタンスメソッド?(クラスメソッドかもしれないのでアップ前に調査)に渡して設定したり描画したりします。
// UIGraphicsGetCurrentContext()メソッドで取得 // 塗りつぶし用と線描画用で分かれている CGContextSetRGBFillColor(_contextRef, CGFloat(r) / 255.0, CGFloat(g) / 255.0, CGFloat(b) / 255.0, CGFloat(alpha)) CGContextSetRGBStrokeColor(_context, CGFloat(r) / 255.0, CGFloat(g) / 255.0, CGFloat(b) / 255.0, CGFloat(alpha)) // 図形を描画するときに上のようなメソッドで設定を行ったcontextRefを渡す CGContextStrokePath(_contextRef)
直線の描画
- CGContextMoveToPoint(_context, CGFloat(x), CGFloat(y))で始点を設定
- CGContextAddLineToPoint(_context, CGFloat(x1), CGFloat(y1))で次の頂点を設定(複数設定すると折れ線や多角形が書ける)
- 最後にCGContextStrokePath(_contextRef)で描画
円の描画
CGContextAddEllipseInRect(_context, CGRectMake(CGFloat(x), CGFloat(y), CGFloat(width), CGFloat(height))) // 楕円の大きさは円が内接する四角形を渡して指定
CGContextStrokePath(_context)
塗りつぶしについて
// 四角形 CGContextFillRect(_contextRef, someRect) // 円 // 楕円の大きさは円が内接する四角形を渡して指定 CGContextFillRect(_contextRef, someRect) // 点を足して...とかしていないので CGContextStrokePath(_contextRef)は不要
画像をStoryBoard上で描画する
内容
iPhone/iPadプログラミングバイブル iOS9/Xcode7/Swift 対応 (smart phone programming bible)
- 作者: 布留川英一
- 出版社/メーカー: ソシム
- 発売日: 2015/10/27
- メディア: 単行本
- この商品を含むブログ (1件) を見る
上の本を参考にiOSのUIViewと戯れています。
- 画像ファイルをプロジェクトに追加する
- 画像をStoryBoardに配置する
- 画像ファイルのサイズとフォーマットについて
- 2倍, 3倍の画像とグループ化した形で追加する
- 画像ファイルの読み込み
画像ファイルをプロジェクトに追加する
プロジェクト本体に追加する場合の手順
- プロジェクト直下のプロジェクト名フォルダを右クリック
- "Add Files to PROJECT_NAME"を選択
- 追加したいファイルを選択して
Add
をクリック
画像をStoryBoardに配置する
- StoryBoardの中で画像を追加したいViewを選択します
- 右側のユーティリティエイアの下側にViewに追加できる要素などが表示できるタブが並んでいます*1が、一番右のタブ(
メディアライブラリ
)を開きます メディアライブラリ
のタブにプロジェクトに追加された画像などの一覧があるので、その中から追加したい要素をStoryBoard上にドラッグします
画像は https://placehold.it/ にて取得しています。
画像ファイルのサイズとフォーマットについて
- プログラミングで指定するテキストや図形のサイズはポイント単位なので、端末ごとの解像度を気にしなくて良い
- 1ポイントのドットのことをスケールと呼ぶ
UIScreen.mainScreen().scale
- 画像はスケールに合わせて自動的に高解像後にはならないのでファイル名に「@2x」「@3x」をつけた2倍, 3倍の解像度の画像を用意する
- 基本的には png を利用する
2倍, 3倍の画像とグループ化した形で追加する
- 元の解像度の画像, 2倍, 3倍の解像度の画像をまとめてプロジェクト名のフォルダにドラッグ & ドロップ
- もし、ダイアローグが開くので、 追加するターゲットが編集中のプロジェクトか確認してOKを押す
画像ファイルの読み込み
UIImage(named: "loadingTarget.png")
で画像ファイルの読み込みUIImage#drawAtPoint(CGPoint)
で描画する位置を指定UIImage#drawInRect(CGRect)
でCGRectで指定した領域へと画像の拡大縮小描画が可能UIImage.size
のプロパティ(width: 幅, height: 高さ)を取得して、それを2倍, 3倍して2倍や3倍に拡大しで描画、など
明日は本気出す(と毎日言っている気も...)。
*1:ライブラリペインというそうです
カスタムビューの配置方法と文字のフォント設定、描画領域のサイズ取得について
今日から少しずつ慣れてこーってことでターミナルでREPLからXCodeに戻ってきたんですが、XCodeって入力してると、にょん!って補完が出てちょっと楽しいですね...。
内容
iPhone/iPadプログラミングバイブル iOS9/Xcode7/Swift 対応 (smart phone programming bible)
- 作者: 布留川英一
- 出版社/メーカー: ソシム
- 発売日: 2015/10/27
- メディア: 単行本
- この商品を含むブログ (1件) を見る
上の本を参考にiOSのUIViewと戯れています。
- カスタムビューの書き方
- 文字の配置について
- フォントの設定の仕方
- サイズの取得の仕方
- カスタムビューをStoryBoardに配置する
カスタムビューの書き方
import UIKit // UIViewから継承して書いていくのは // AndroidのCustomViewを書くようなノリなのでしょうか class StringEx : UIView { // 描画時に呼び出されます override func drawRect(rect: CGRect) { // ここに描画内容を書く } }
文字の配置について
// UIViewクラスのインスタントメソッド内で // stringはString型のリテラル string.drawAtPoint(CGPointMake(CGFloat(x), CGFloat(y)))
Androidのひよっこなので、TextViewみたいなのがあって、それを配置してからそこに描画する文字を属性として設定する、みたいなのが基本かと思っていたので、Stringオブジェクトのインスタンスメソッドで描画処理がかけることに少し驚いて検索してみたのですが。
http://secondflush2.blog.fc2.com/blog-entry-1002.html
// ターミナルで叩いてみてSwiftそのもののStringには // そんなメソッドないみたいです 113> "Test".drawAtPoint repl.swift:113:1: error: value of type 'String' has no member 'drawAtPoint' "Test".drawAtPoint ^~~~~~ ~~~~~~~~~~~ // シグネチャが間違っている時に出るエラー // repl.swift:116:20: error: argument passed to call that takes no arguments
フォントの設定の仕方
let attrs = [ // フォントをメソッドで生成する場合 // (system/bold/italic)FontOfSize(size : CGFloat) // で標準/太字/斜体のフォントが指定できる // iOSで利用出来るフォントである必要があるが、フォント名をUIFontのイニシャライザ // に渡すとそのフォントに対応したUIFontのオブジェクトが利用出来る NSFontAttributeName: UIFont.systemFontOfSize(CGFloat(size)), NSForegroundColorAttributeName: color ] // フォントの設定が入ったディクショナリを // withAttributesのパラメータとして渡す str.drawAtPoint(CGPointMake(CGFloat(x), CGFloat(y)), withAttributes: attrs)
サイズの取得の仕方
// strの文字列を設定したパラメータによって描画した場合の // 描画領域のサイズを表すGCSizeクラスが帰ってきます。 // struct GCSize { // var width: CGFloat // var height: CGFloat // } let attrs = [ NSFontAttributeName: UIFont.systemFontOfSize(CGFloat(size))] return str.sizeWithAttributes(attrs)
カスタムビューをStoryBoardに配置する
http://qiita.com/kikuchy/items/f1d6731d804b63cf7a29
上の記事を参考にやってみました。
手順は、
- カスタムビューの親クラスにあたるビューをStoryBoardに配置
- 配置したビューをクリック
- 右側のユーティリティエリアの
show the Identity Inspecter
と吹き出しが出るタブ(アイデンティティインスペクタ
)を開く Custom Class
の項目にカスタムビューのクラス名を追加
ひとまず、しばらくはサンプルなぞってきゃっきゃしているだけ感じです。
JavaScriptではUI作るための引き出しがなくてMVCとかは多少はわかっても実際いろいろ動きを作るのが遅くて*2、Androidの時は逆に最初に一通りwidgetクラス触って少しだけ救われたので、とりあえず面白がれる範囲でやっていこうかと思います。
*1:本当はNSStringが拡張されているけれど、SwiftからはObjective-CのNSStringはStringとして見える
*2:この辺とかで時間切れしてたりする http://woshidan.hatenablog.com/entry/2015/06/15/024121
はてな教科書の「プログラミング言語 Swift」を読んでます 7
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
のんびり読んでいきます。一旦ラストォ!
Generics
特定の型ではなくて、同じ種類ならどの型に対しても対応したい、みたいな場合に使います。
Javaだとだいたい一文字で表されていることが多いのですが、Swiftの場合、一文字ではない...のでしょうか。
配列など集合を扱うクラスなどで使うことが多そうです。
と思ったら、後ろの方の関数の例に func someFunction<T>()
とあって安心です...。
102> class Printer<Content> { 103. var content : Content 104. init(content: Content) { 105. self.content = content 106. } 107. func printContent() { 108. print(content) 109. } 110. } 111> Printer<String>(content:"Print").printContent() Print 112> Printer<Int>(content: 1234).printContent() 1234
Associated types and type constraints
protocolにはassociatedtype ItemType
のように関連する型を定義する機能があります。
protocolに準拠する側では、typealias ItemType = Item
のように書いてその型を指定できます。
こうすることでprotocolを引数に取る関数などにおいてもその型を抽象化できます。
また、<Type: SomeProtocol>
のようにすることで特定のprotocolに準拠していたり、特定の型を継承している型であることを指定でき、さらにwhere節でその型について制約をかけることも可能です。
Access control
public
は完全に公開され、どこからでもアクセス可能internal
はモジュール内部からだけアクセスprivate
はそのファイル内からだけアクセス- デフォルトは
internal
- テスト用に
internal
のメソッドなどにアクセスが必要な場合は@testable import SomeModule
と書いて、テスト時のビルド設定をEnable Testability
を有効にします
protectedはないのですか...!
Availability
実行されるプラットフォームやバージョンによって利用できない関数などを表すために @available 属性が利用できます。
とりあえずここまでで一旦おしまいで次からViewをいじいじします。
はてな教科書の「プログラミング言語 Swift」を読んでます 6
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
のんびり読んでいきます。もうちょい!
Casting
isでインスタンスの型を確認.
84> class Cat: Animal { 85. // 86. // A'(A をオーバーライド。ここに required 修飾子がないと、サブクラス PersianCat に、このイニシャライザのオーバーライドを強制できない) 87. // 88. required init() { 89. super.init() 90. } 91. } 92> class PersianCat: Cat {} 93> var persianCat = Per Available completions: PermutationGenerator PersianCat 93> var persianCat = PersianCat() persianCat: PersianCat = { __lldb_expr_47.Cat = { __lldb_expr_41.Animal = { name = "unknown" } } } 94> persianCat is Cat $R8: Bool = true
as
でキャストだが、スーパークラスにキャストする場合は、 as
, サブクラスにキャストする場合は、as?(Optionalで失敗したらnil)
かas!(キャスト失敗でランタイムエラー)
になります。
95> persianCat as Cat $R9: PersianCat = { __lldb_expr_47.Cat = { __lldb_expr_41.Animal = { name = "unknown" } } } 96> var cat = Cat() cat: Cat = { __lldb_expr_41.Animal = { name = "unknown" } } 97> cat as? PersianCat $R10: PersianCat? = nil 98> cat as! PersianCat Could not cast value of type 'Cat' (0x101336ab8) to 'PersianCat' (0x101336fe8). Execution interrupted. Enter code to recover and continue. Enter LLDB commands to investigate (type :help for assistance.)
どちらかというと、キャストに失敗したらelseみたいな例文が自信ないです...。
if let swift = source as? SwiftFile { compiled.append(swift.compile()) } else { compiled.append(source) }
128> if cat as? PersianCat { 129. print("persian") 130. } repl.swift:128:8: error: optional type 'PersianCat?' cannot be used as a boolean; test for '!= nil' instead if cat as? PersianCat { ^ (( ) != nil) 128> if let persia = cat as? PersianCat { 129. print("persian") 130. }
letなどブロックの中で使う変数の定義が条件式に入った場合のif文がよくわからないみたいなので気をつけてみようと思います。
Protocol
いわゆるインタフェース。
- プロパティ
- メソッド
- イニシャライザ
- subscript*1
の宣言ができます。
また、メソッドは、 { get }
, { get, set }
で可変かを指定できます。
また、Protocol同士も継承できます。
1> protocol Man { 2. var firstName: String { get } 3. var lastName: String { get } 4. init(firstName: String, lastName: String) 5. func printFullName() 6. } 7> struct Japanese : Man { 8. var firstName: String 9. var lastName: String 10. init(firstName: String, lastName: String) { 11. self.firstName = firstName 12. self.lastName = lastName 13. } 14. func printFullName() { 15. print("\(firstName)\(lastName)") 16. } 17. } 18> struct American : Man { 19. var firstName: String 20. var lastName: String 21. init(firstName: String, lastName: String) { 22. self.firstName = firstName 23. self.lastName = lastName 24. } 25. func printFullName() { 26. print("\(lastName) \(firstName)") 27. } 28. } 29> var Taro = Japanese(firstName: "Yoshida", lastName: "Taro") Taro: Japanese = { firstName = "Yoshida" lastName = "Taro" } 30> var Ken = American(firstName: "Yoshida", lastName: "Ken") Ken: American = { firstName = "Yoshida" lastName = "Ken" } 31> Taro.printFullName() YoshidaTaro 32> Ken.printFullName() Ken Yoshida 33> struct Arian : Man { 34. var firstName: String { set {} } 35. 36. init(firstName: String, lastName: String) { 37. self.firstName = firstName 38. self.lastName = lastName 39. } 40. func printFullName() { 41. print("\(lastName) \(firstName)") 42. } 43. } repl.swift:34:29: error: variable with a setter must also have a getter var firstName: String { set {} } ^
Protocolは複数継承させることができますが、複数の protocol に適合していることを protocol<SomeProtocol, AnotherProtocol>
と表現できるそうです。
33> Taro as? protocol<Man> $R0: Man? = (payload_data_0 = 0x0000000100509980 -> 0x00000001004fdde0 , payload_data_1 = 0x0000000000000000, payload_data_2 = 0x0000000000000000, instance_type = 0x00000001004f1218 nominal type descriptor for __lldb_expr_6.Japanese + 72, protocol_witness_0 = 0x00000001004f1110 protocol witness table for __lldb_expr_6.Japanese : __lldb_expr_4.Man in __lldb_expr_6) { payload_data_0 = 0x0000000100509980 -> 0x00000001004fdde0 payload_data_1 = 0x0000000000000000 payload_data_2 = 0x0000000000000000 instance_type = 0x00000001004f1218 nominal type descriptor for __lldb_expr_6.Japanese + 72 protocol_witness_0 = 0x00000001004f1110 protocol witness table for __lldb_expr_6.Japanese : __lldb_expr_4.Man in __lldb_expr_6 } 34> protocol Animal {} 35> Taro as? protocol<Man, Animal> $R1: protocol<Animal, Man>? = nil
Extension
メタプロらしいものです。
computed プロパティやメソッド、イニシャライザや subscript を追加できますが、storedプロパティは追加できません。
36> extension Int { 37. var hex: String { 38. return String(self, radix: 16) 39. } 40. } 41> 245.hex $R2: String = "f5"
また、extension は protocol も拡張でき、Protocol Extensions
といいます。
エラー処理
- 例外を発生するメソッドに
throws
をつける - 例外を投げる時は、
throw
- 例外は、
ErrorType
を継承した自分のクラスで定義できる - エラーを投げる関数の前に
try
をつけて、その関数をdo { } catch ErrorType { } ...
ブロックで囲む- 実際にエラーが発生しないことがわかっている場合は
try!
にしてエラーハンドリングしないことを明示できる(ただし実際に発生したらランタイムエラーになる) try?
にすると返り値がオプショナルになって、例外が発生した時はnilが返る- キャッチされなかったエラーはそのブロックの呼び出し元に伝播していきます
- 実際にエラーが発生しないことがわかっている場合は
- エラーを throws するクロージャの案件はおかわりで...
42> enum SomeError : ErrorType { 43. case Empty 44. case Numeric 45. } 46> func throwError(str: String) throws -> String { 47. if str.isEmpty { 48. throw SomeError.Empty 49. } 50. if let num = Int(str) { 51. throw SomeError.Numeric 52. } 53. return str 54. } 55> do { 56. let res = try throwError("") 57. print(res) 58. } catch SomeError.Empty { 59. print("Empty") 60. } catch SomeError.Numeric { 61. print("Numeric") 62. } Empty 63> do { 64. let res = try throwError("123") 65. print(res) 66. } catch SomeError.Empty { 67. print("Empty") 68. } catch SomeError.Numeric { 69. print("Numeric") 70. } Numeric 71> do { 72. let res = try throwError("abc") 73. print(res) 74. } catch SomeError.Empty { 75. print("Empty") 76. } catch SomeError.Numeric { 77. print("Numeric") 78. } abc
defer
関数の最後に必ず実行したい処理がある場合、defer 文を利用することができます。
79> func deferTest(str: String) { 80. defer { 81. print(str) 82. } 83. print(str + str + str) 84. } 85> deferTest("ABCD!") ABCD!ABCD!ABCD! ABCD! // 途中でreturnする場合...? 86> func deferTest2(str: String) { 87. defer { 88. print(str) 89. } 90. return 91. print(str + str + str) 92. } 93> deferTest2("ABCD!") ABCD!ABCD!ABCD! ABCD! // 途中で例外を投げる場合 94> func deferTest2(str: String) throws { 95. defer { 96. print(str) 97. } 98. throw SomeError.Empty 99. print(str + str + str) 100. } 101> deferTest2("ABCD!") ABCD! warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available. 102>
*1:ArrayやDictionaryのように[]の記法でクラスに値を変えさせるあれ
はてな教科書の「プログラミング言語 Swift」を読んでます 5
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
イニシャライザが難しかったのですが、のんびり読んでいきます。
Inheritance
class名の右に:
をつけてスーパークラスを指定することでそのクラスを継承することができます。
スーパークラスの実装を明示的に利用する場合は、super
キーワードを用います。
1> class Man { 2. func greeting() -> String { 3. return "Hello" 4. } 5. } 6> class Student : Man { 7. override func greeting() -> String { 8. return "\(super.greeting()), Teacher" 9. } 10. } 11> let taro: Man = Student() taro: Student = { __lldb_expr_1.Man = {} } 12> taro.greeting() $R0: String = "Hello, Teacher"
final
キーワードをclass
やfunc
につけることで継承を制限することができます。
Initializers and deinitializers
Initializers
- class, enum, structではイニシャライザが定義できる
- イニシャライザでは、Optional型ではないstoredプロパティ(let, varをつけるいわゆる普通のインスタンス変数ないしクラス変数)で、初期値が設定されていないものをすべて初期化する必要がある
- イニシャライザは複数定義可能で、メソッドとは異なり第一引数からラベルを明記する
- 型が同じでもラベルによってイニシャライザが区別される
- 下記の条件で、class はデフォルトで空のイニシャライザを持つ
- イニシャライザが一つも定義されておらず
- かつイニシャライザで初期化するべき stored プロパティが存在しない
- 下記の条件で、 structは全ての初期化すべき stored プロパティを定義順に指定するデフォルトのイニシャライザを持つ
- イニシャライザが一つも定義されていない場合
値型のイニシャライザ
- 値型は
enum
,struct
- enum型のイニシャライザについては http://qiita.com/_mpon/items/4491d19fa50b2039af35 など
http://qiita.com/cotrpepe/items/3052d91468f1b852582a http://qiita.com/qoAop/items/a28e3649feaf38af1134
// 参考: http://qiita.com/_mpon/items/4491d19fa50b2039af35 18> enum Size { 19. case Small, Medium, Large 20. 21. // 引数なしコンストラクタ 22. init() { 23. self = .Small // デフォルト値の設定など 24. } 25. } 26> Size() $R3: Size = Small
// 値型の場合は self.init で自身のイニシャライザを呼び出すことができるのenumのそれがわからない..。 27> enum Size { 28. case Small, Medium, Large 29. 30. // 引数なしコンストラクタ 31. init() { 32. self = .Small 33. } 34. init(type: Int) { 35. if type % 3 == 0 { 36. self = .Medium 37. } else { 38. self = self.init 39. } 40. } 41. } repl.swift:38:25: error: cannot assign value of type '_ -> _' to type 'Size' self = self.init ~~~~~^~~~ // Structの場合は https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html より 1> struct Size { 2. var width = 0.0, height = 0.0 3. } 4. struct Point { 5. var x = 0.0, y = 0.0 6. } 7> 8> struct Rect { 9. var origin = Point() 10. var size = Size() 11. init() {} 12. init(origin: Point, size: Size) { 13. self.origin = origin 14. self.size = size 15. } 16. init(center: Point, size: Size) { 17. let originX = center.x - (size.width / 2) 18. let originY = center.y - (size.height / 2) 19. self.init(origin: Point(x: originX, y: originY), size: size) 20. } 21. }
参照型のイニシャライザ
- designated イニシャライザはclass中の初期値が与えられていないletやvarのstoredプロパティの値をすべて定義する
- ほかのイニシャライザには
convenience
修飾子をつける- convenienceイニシャライザはdesignated イニシャライザを呼び出さなければいけない
- クラスを継承している場合は、必ずsuperclassのイニシャライザを呼び出さなければいけない
42> class Initial { 43. var name: String 44. init() { 45. name = "Sample" 46. } 47. 48. convenience init(initName: String) { 49. self.init() 50. self.name = initName 51. } 52. func display() { 53. print(name.substringToIndex(name.startIndex.advancedBy(1))) 54. } 55. } 56> Initial().display() S 57> Initial(initName: "Example").display() E
SubクラスがSuperクラスのdesignated イニシャライザを定義していない場合、スーパークラスの designated イニシャライザが利用できます。
27> class Super { 28. init() { 29. print("Super") 30. } 31. } 32> class Sub : Super {} 33> Sub() Super $R1: Sub = { __lldb_expr_11.Super = {} }
required 修飾子で実装を強制することもできます。
34> class Super { 35. init() { 36. print("Super") 37. } 38. required convenience init(printString: String) { 39. self.init() 40. print(printString) 41. } 42. } 43> class Sub : Super {} 44> Sub() Super $R2: Sub = { __lldb_expr_19.Super = {} } 45> Sub(printString: "Test") Super Test $R3: Sub = { __lldb_expr_19.Super = {} }
Failable Initializers
init?
と?
をつけたイニシャライザは与えられた引数によっては初期化を失敗させてnilを返すようにできる- そのイニシャライザの返り値をしては、Optionalとなる
Deinitializers
クラスのインスタンスが破棄されるときに実行したい処理はデイニシャライザ(deinit {...}
)にて定義できる。
新卒向け社内研修でテーブル設計と正規化の基本の話をしました
新卒向け社内研修でテーブル設計と正規化の基本の話をしました。
理論から学ぶデータベース実践入門 ~リレーショナルモデルによる効率的なSQL (WEB+DB PRESS plus)
- 作者: 奥野幹也
- 出版社/メーカー: 技術評論社
- 発売日: 2015/03/10
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (17件) を見る
いま新卒の方々はRails tutorialを進めながら「理論から学ぶデータベース実践入門 ~リレーショナルモデルによる効率的なSQL」を読んでいるところなのですが、中には入社以前にはWeb系のプログラミング経験のない方もいらっしゃいます。
その状態で上記の本を読み進めるのは少しつかみにくいところもあるだろうな、ということで、この資料に関してはかなり基本に絞り、演習で設計から第1から第3正規化の一連のプロセスについて手を動かしてみて経験値の底上げをしてもらうという構成にしました*1。
理論的な背景をもちろん抑える必要はあるのですが、何度か手を動かしてみて頭の中に回路を作ってみる、というのも車の両輪みたいに大切で、一人でも正規化の手続きの流れが追えるようにしたつもりです。
「変わりそうな値を主キーにしてはいけない」「商品の値段が変わった場合、過去の注文の合計金額を変えないためにはどうしたらよいか」「あとから特定の状態になった日を知りたくなるような場合があるときは、どうしたらよいか」
他にもいろいろあるんですけど、そういったもう少し応用的な内容については、少しだけ演習の合間に声をかけさせていただきましたが、興味を持っていただけたら他の実践テクニックに寄せた本なども読んでみると面白いと思います。
自分が読んだ中でオススメは下記です。
- 作者: 藤島一月男,奥恵
- 出版社/メーカー: 技術評論社
- 発売日: 2013/03/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ
- 作者: ミック
- 出版社/メーカー: 翔泳社
- 発売日: 2012/03/16
- メディア: 単行本(ソフトカバー)
- 購入: 21人 クリック: 316回
- この商品を含むブログ (23件) を見る
SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)
- 作者: ミック
- 出版社/メーカー: 技術評論社
- 発売日: 2015/04/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (7件) を見る
- 作者: Bill Karwin,和田卓人,和田省二,児島修
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/01/26
- メディア: 大型本
- 購入: 9人 クリック: 698回
- この商品を含むブログ (42件) を見る
*1:この本を去年の新卒に勧めたのは私なのですが、去年の新卒は非常にすごい人ぞろいでして...