>100 Views
September 28, 16
スライド概要
Swift 3 の新しくなったところのうちから、目立つところを6つほど、意味的な観点を大事にしながらざっくり紹介しました。2016/09/28 ISAO meetup でお話しした発表資料です。
※ Docswell での公開に移行する直前の Slideshare での閲覧数は 3,433 でした。
正統派趣味人プログラマー。プログラミングとは幼馴染です。
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ ද໘͔Β͜ͱ͍͘ʹ͑ݟΖΛத৺ʹհ *4"0.FFUVQPO &;/&5۽୩༑ IUUQF[OFUKQ 4XJGU
۽୩༑ 5PNPIJSP,VNBHBJ ⾣ 4XJGU͕ޠݴେ͖Ͱ͢ʂ ⾣ ΈΜͳͰָ͠Ήษڧձ͕େ͖Ͱ͢ʂ ⾣ ϓϩάϥϛϯάͷָ͠͞Λ͍͖͍͑ͯͨɻ !FT@LVNBHBJ UPNPIJSPLVNBHBJ $PEF1JFDFGPSNBD04 IUUQF[OFUKQ 9DPEFపఈղઆ
$PEF1JFDFGPSNBD04 ษڧձΛָ͠ΉΞϓϦ ⾣ ιʔείʔυΛ5XJUUFSͱ(JTUʹಉ࣌ߘ ⾣ ίʔυཝΛۭʹ͢Εɺී௨ʹπΠʔτՄೳ ⾣ ϋογϡλάΛઃఆͰ͖Δʗ͚Εͳ͍ #swift
ษڧձΛ։࠵͍ͯ͠·͢ɻ Θ͍Θ͍ɺָ͘͠ɺ ΈΜͳͰޠΒ͑ΔॴΛࢦͯ͠ ԣJ1IPOF։ൃऀษڧձ ୈճ݄ͷ։࠵ʢඪʣ ZJEFW ˏԣɾഅंಓ IUUQTBUOEPSHHSPVQTZJEFW ΧδϡΞϧ4XJGUษڧձ ΈΜͳͰ4XJGU ෮शձ DTXJGU !ԣɾ੨༿ NJOOB@EF@TXJGU ˏौ୩ ୈճΛ݄ʹ։࠵ ୈճ݄ʹ։࠵༧ఆ IUUQTBUOEPSHHSPVQTDTXJGU IUUQDTXJGUDPOOQBTTDPN
NPPLNPPLSBEJP Ќ൛ ϜοΫϜοΫϥδΦ ۽୩ͱ៸໘͕ϓϩάϥϛϯάίʔυͷ͔Β ௌ͑ͯ͘͜ΔʹࣖΛָ͚ͯ͠ΉϥδΦ ຖ݄ୈ̎ɾୈ̐ ݄༵ ʹ৴ IUUQNPPLNPPLSBEJPDPNB ⾣ ୈ̍ ʰϓϩάϥϛϯάͱࢲͨͪʱ ⾣ ୈ̎ ʰྻܕڍʱ ⾣ ୈ̏ ʰίϝϯτʱ ⾣ ୈ̐ ʢ݄ʹ৴༧ఆʣ
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ ද໘͔Β͜ͱ͍͘ʹ͑ݟΖΛத৺ʹհ
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ ද໘͔Β͜ͱ͍͘ʹ͑ݟΖΛத৺ʹհ 4XJGUͷίϯηϓτ "1*໋໊نଇͷओͳͱ͜Ζ *NQMJDJUMZ6OXSBQQFE0QUJPOBM 4FRVFODFͷ৽ػೳ ΠϯσοΫε$PMMFDUJPO੍͕ ޚ !OPFTDBQFΫϩʔδϟʔ
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ 4XJGUͷίϯηϓτ
4XJGUͷίϯηϓτ 4XJGUͷඪ ⾣ 4XJGUޠݴΛ֬ఆɾख़ͤ͞Δ ͦͷͨΊʹιʔεޓੑͷഁյࣙ͞ͳ͍ ⾣ 4XJGUҎ߱Ͱͷ ιʔείʔυͷޓੑΛࢦ͢ʢྗඪʣ ⾣ 4XJGUҎ߱ͷιʔεޓഁյ Ө࠷͕ڹখͳʹݶΔΑ͏ʹྀ͢Δ
4XJGUͷίϯηϓτ ͍ͨ͠ͱ͜Ζ ⾣ ৽͍͠"1*ΨΠυϥΠϯ ⾣ ༷ޠݴΛચ࿅ ⾣ 0CKFDUJWF$$ͷίʔυΛ4XJGUจԽʹ༥߹ ⾣ ίϯύΠϥ*%&ͷ্࣭ ⾣ 4XJGUύοέʔδϚωʔδϟʔ
4XJGUͷίϯηϓτ ண ࣗޠݴମͷ҆ఆԽΛਤΓ ଞڥͷҠ২ੑΛݟਾ͑Δ
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ "1*໋໊نଇͷओͳͱ͜Ζ
"1*໋໊نଇͷओͳͱ͜Ζ 4XJGU"1*%FTJHO(VJEFMJOFT ⾣ 4XJGUͷ"1*Λॻͨ͘Ίͷࢦ ⾣ 4XJGUͷཱͬͨมԽ͕ू͞Ε͍ͯΔҹ IUUQTTXJGUPSHEPDVNFOUBUJPOBQJEFTJHOHVJEFMJOFT
"1*໋໊نଇͷओͳͱ͜Ζ "1*%FTJHO(VJEFMJOFT֓ཁ ⾣ ࣗવͳӳͰޠ௲ΕΔΑ͏ʹ ⾣ શͯͷݴ༿͕໌֬ͳҙຯΛؚΉΑ͏ʹ ⾣ ໊લͷ͚ํ w ϑΝΫτϦʔϝιουͱΠχγϟϥΠβʔ w ϝιουʢ෭࡞༻Λ͏߹ɺΘͳ͍߹ʣ w ਅِΛฦ͢߹ w ϓϩτίϧ w ઐ༻ޠͷ͍Ͳ͜Ζ w Φʔόʔϩʔυطఆͷར༻ʹ͍ͭͯ ⾣ େҬؔΑΓϝιου༏ઌͰఆٛ͢Δ
4XJGU"1*%FTJHO(VJEFMJOFT ಛʹ͓͖͍ͬͯͨͱ͜Ζ
"1*໋໊نଇͷओͳͱ͜Ζ ໊ܕม໊ ⾣ Ұൠʹɺ໊લ໊ࢺͰ͚ͭΔ ⾣ ਅِΛද͢ϓϩύςΟʔ໊ɺରͷओுͰද͢ݱΔ // 型は名詞で名前をつける。 struct Queue { … } // 変数名は名詞でつける。 let queue = Queue() // 真偽値プロパティーは主張重視。配列が空であるか。 items.isEmpty
"1*໋໊نଇͷओͳͱ͜Ζ ϝιουͱϥϕϧ͚ ⾣ ѻ͏ओମϥϕϧΛল͘ͱɺࣗવͳදͳʹݱΔ ⾣ ҐஔಛఆͳͲͷલஔࢺϥϕϧͰද͢ݱΔ // item は items が扱う主体 items.add(item) // index は items が扱う主体ではない items.remove(at: index) // 複数で位置を示すときは前置詞を名前に含めることも items.moveTo(x: 3, y: 5)
"1*໋໊نଇͷओͳͱ͜Ζ ໊ؔࣗͷӨʹڹΑͬͯ ⾣ ࣗͷӨ͕͋ڹΔ͔Ͱɺ໊લΛม͑Δ ⾣ ໊લ໊͕ࢺ͔ܥಈࢺͰ͔ܥɺ໋໊ํ๏͕มΘΔ // 名詞系で、自身に影響しない場合は、名詞そのまま。 let answer = value.squareRoot() // 名詞系で、自身に影響する場合は“form”接頭辞。 value.formSquareRoot() // 動詞系で、自身に影響ないなら“-ed”か“-ing”接尾辞。 let answer = value.divided(by: 3) // 動詞系で、自身に影響するなら、動詞そのまま。 value.divide(by: 3)
"1*໋໊نଇͷओͳͱ͜Ζ ਅِΛఆ͢Δϝιου໊ ⾣ ରͷओுͱͯ͠ΈऔΕΔ໊લʹ͢Δ ⾣ ී௨ͷϝιουͱผͷنଇͰ໊લΛ͚ͭΔ // 範囲が、ある範囲と、重なる点があるか if range1.overlaps(range2) { … } // 配列が、要素を、含んでいるか if items.contains(item) { … } // 要素を返してるのか、要素を含むか判定してるのか。 let answer = items.contained(item) { … }
"1*໋໊نଇͷओͳͱ͜Ζ ྻࢠڍͷ໊લখจࣈ ⾣ -PXFS$BNFM$BTFͰ໊લΛ͚ͭΔ // 列挙子の名前は小文字で始める。 enum Drink { case coffee case tea case water }
"1*໋໊نଇͷओͳͱ͜Ζ
େҬؔΑΓϝιουͰ
⾣ ϝιουͳΒɺॴଐͰҙຯ͕໌ྎʹͳΔ
⾣ ॴଐ͕ͳ͍ͱ͖׳शతʹదͳΒɺେҬؔΛ͏
// キューの最初、と表現できる。
extension Queue {
func first -> Element? { … }
}
// 所属が定まらない場合に、大域関数として扱う。
func max(_ x: Int, _ y: Int, _ z: Int)
// 数値の絶対値、所属はあっても abs(x) が慣習的。
func abs(_ x: Int) -> Int
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ *NQMJDJUMZ 6OXSBQQFE 0QUJPOBM
*NQMJDJUMZ 6OXSBQQFE 0QUJPOBM *NQMJDJUMZ6OXSBQQFE0QUJPOBMͱ ⾣ தΛ҉తʹΞϯϥοϓͯ͘͠ΕΔΦϓγϣφϧ ⾣ ͏·ͰʹઈରʹΛ༻ҙͰ͖Δ໘Ͱศར class Controller : UIViewController { @IBOutlet var titleLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() titleLabel.text = "ISAO meetup" } } ! や ? で中身を取り出す操作をしなくても 自動で取り出される
*NQMJDJUMZ 6OXSBQQFE 0QUJPOBM %FQSFDBUFE let value: Type! ⾣ 0QUJPOBM *60ଐੑͱ͍͏ཱͪҐஔʹมߋ w ҉ΞϯϥοϓͳΦϓγϣφϧܕഇࢭ ʢ༧ఆʁʣ ⾣ Type!ͷΑ͏ͳఆٛࣗମ݈ࡏ ⾣ มΛ͏ͱɺ҉Ξϯϥοϓʢैདྷ௨Γʣ ⾣ ܕਪͰType?ͱͯ͠ѻΘΕΔ ⾣ ܕύϥϝʔλʔʹ͑ͳ͍ʢϧʔϧ্ʣ
*NQMJDJUMZ 6OXSBQQFE 0QUJPOBM มఆٛͱܕਪ ⾣ มఆٛɺࠓ·ͰͲ͓ΓՄೳ ⾣ ଞͷมʹೖ͢Δͱɺී௨ͷ0QUJPOBMʹͳΔ // 型に ! を添えて定義する(従前どおり) let implicitly: Int! = 100 // 型明記せずに受けると、その変数は普通の Optional 型 let optional = implicitly Int?
*NQMJDJUMZ 6OXSBQQFE 0QUJPOBM
ෆ༻ҙʹ࣋ͪӽ͞ͳ͍
⾣ ผͷมʹ࣋ͪग़͢ͱ͖ʹOJMͷѻ͍Λ໌֬Խ
⾣ ଈ࣌ղফ͢Δ͔ɺ໌ࣔΞϯϥοϓঢ়ଶͰ࣋ͪӽ͔͢
// Int! を返す関数があったとき …
func something() -> Int! {…}
// 暗黙アンラップとして即使用する方法(受け手は戻り値の型)
let result = something().advanced(by: 1)
// 速やかに解消する方法(受け手は Int 型)
let result = something()!
// nil の可能性を残して先へ(受け手は Int? 型)
let result = something()
*NQMJDJUMZ 6OXSBQQFE 0QUJPOBM ෆ༻ҙʹ࣋ͪӽ͞ͳ͍ ⾣ ܕύϥϝʔλʔʹ͑ͳ͍ʢ͜ͱʹͳ͍ͬͯΔʣ ⾣ જࡏతʹOJM͕࣋ͪӽ͞ΕΔՄೳੑΛճආ let values = Array<Int!> JNQMJDJUMZVOXSBQQFEPQUJPOBMTBSFPOMZ BMMPXFEBUUPQMFWFMBOEBTGVODUJPOSFTVMUT // Int! 型のまま持ち歩くのを防ぐことで、 // 取り出した時に初めて nil だったことに気づくのを予防
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ 4FRVFODFͷ৽ػೳ
4FRVFODFͷ৽ػೳ γʔέϯεͱ ⾣ 4FRVFODFϓϩτίϧʹ४ܕͨ͠ڌ ⾣ GPSʜJOߏจͰ܁Γฦ͠ॲཧ͕Ͱ͖Δ for value in 0 ..< 100 { } CountableRange<Int> : Sequence
4FRVFODFͷ৽ػೳ खܰʹѻ͏ͨΊͷػೳ ⾣ γʔέϯεܕΛ؆୯ʹ࡞Δ w TFRVFODF pSTUOFYU w TFRVFODF TUBUFOFYU ⾣ ݅ʹ͋ͬͨཁૉΛ͚ͭݟΔ w pSTU XIFSF
γʔέϯεΛ࡞Δ
γʔέϯεΛ࡞Δ ϑΟϘφονྻΛ࡞Δͱ͖ 1 1 1 1 2 2 3 5 1 1 1 1 3 " ࣗ࡞ͷ4FRVFODF࡞Ͱܕ # "OZ4FRVFODFͰ࡞ $ TFRVFODF pSTUOFYU Ͱੜ % TFRVFODF TUBUFOFYU Ͱੜ 1
γʔέϯεΛ࡞Δ
"ࣗ࡞ͷ4FRVFODF࡞Ͱܕ
struct Fibonacci : Sequence {
struct Iterator : IteratorProtocol {
fileprivate var data = (0, 1)
mutating func next() -> Int? {
defer {
data = (data.1, data.0 + data.1)
}
return data.1
}
}
func makeIterator() -> Iterator {
return Iterator()
}
}
γʔέϯεΛ࡞Δ
#"OZ4FRVFODFͰ࡞
let fibonacci = AnySequence { () -> AnyIterator<Int> in
var data = (0, 1)
return AnyIterator {
defer {
data = (data.1, data.0 + data.1)
}
return data.1
}
}
γʔέϯεΛ࡞Δ $TFRVFODF pSTUOFYU Ͱੜ var previous2 = 0 let fibonacci = sequence(first: 1) { previous1 in defer { previous2 = previous1 } return previous1 + previous2 }
γʔέϯεΛ࡞Δ
%TFRVFODF TUBUFOFYU Ͱੜ
let fibonacci = sequence(state: (0, 1)) {
(state: inout (Int, Int)) -> Int? in
defer {
state = (state.1, state.0 + state.1)
}
return state.1
}
݅ʹ͋ͬͨཁૉΛ͚ͭݟΔ
݅ʹ͋ͬͨཁૉΛ͚ͭݟΔ ࢦఆ݅Λ࠷ॳʹຬͨ͢ ⾣ ҎલGPSʜJOͰ୳͢ඞཁ͕͋ͬͨ ⾣ 4XJGUͰpSTU XIFSF Ͱ୳ͤΔ // Swift 3 での探し方 let value: Int? = fibonacci.first { $0 > 100 } // Swift 2 での探し方 var value: Int? { for v in fibonacci where v > 100 { return v } return nil }
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ ΠϯσοΫε$PMMFDUJPO੍͕ޚ
ΠϯσοΫε੍ޚ$PMMFDUJPO͕୲ 4XJGUͰΠϯσοΫε͕୲ ⾣ ҎલΠϯσοΫεࣗମ͕લؔޙΛѲ͍ͯͨ͠ ⾣ 'PSXBSE*OEFY #JEJSFDUJPOBM*OEFY ʜ // 次のインデックスを取得 let next = index.successor() // 前のインデックスを取得 let previous = index.predeessor()
ΠϯσοΫε੍ޚ$PMMFDUJPO͕୲ 4XJGUͰίϨΫγϣϯ͕୲ ⾣ ࠓޙίϨΫγϣϯ͕લؔޙΛѲ͢Δ ⾣ $PMMFDUJPO #JEJSFDUJPOBM$PMMFDUJPO ʜ // 扱うインデックスの範囲 let indices = items.indices // あるインデックスの次を取得 let next = items.index(after: index) // あるインデックスの前を取得 let previous = items.index(before: index)
ΠϯσοΫε੍ޚ$PMMFDUJPO͕୲ ΠϯσοΫε੍͕͢ޚΔσϝϦοτ ⾣ ΠϯσοΫε͕࿈ଓੑΛද͚ͳ͠ݱΕ͍͚ͳ͍ ⾣ ࣮࣭ɺίϨΫγϣϯຖʹΠϯσοΫε͕ܕඞཁ ໊ܕͷΠϯσοΫε Kudo Kumagai predecessor successor Sato Tanaka successor
ΠϯσοΫε੍ޚ$PMMFDUJPO͕୲ ίϨΫγϣϯ੍͕͢ޚΔϝϦοτ ⾣ ΠϯσοΫεͷൣғίϨΫγϣϯ͕Ѳ͍ͯ͠Δ ⾣ ී௨ͷܕΛΠϯσοΫεͱͯ͑͠Δ ໊ܕ Kudo 開始インデックス index(before: "Kudo") Kumagai index(after: "Kumagai") Sato index(after: "Sato") Tanaka 終端インデックス
ΠϯσοΫε੍ޚ$PMMFDUJPO͕୲ ҠಈڑίϨΫγϣϯ͕୲ ⾣ BEWBODFEEJTUBODFίϨΫγϣϯʹ࣮ ⾣ ΠϯσοΫεࣗମʹݪଇɺ࣮͞Εͳ͍ // 指定した距離だけ先のインデックスを取得 items.startIndex.advancedBy(5) items.index(items.startIndex, offsetBy: 5) // インデックス間の距離を取得 items.startIndex.distanceTo(items.endIndex) items.distance(from: items.startIndex, to: items.endIndex)
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ !OPFTDBQFΫϩʔδϟʔ
!OPFTDBQFΫϩʔδϟʔ Ϋϩʔδϟʔͱ ⾣ ଈ੮Ͱ࡞ΕΔແ໊ؔ ⾣ पғͷมΛऔΓࠐΜͰ͑Δ var currentValue = 0 let closure = { () -> Int in currentValue += 1 内側で、外の変数をそのまま使える return currentValue }
!OPFTDBQFΫϩʔδϟʔ Ϋϩʔδϟʔͷطఆͷੑ࣭มߋ ⾣ 4XJGUͰ!FTDBQJOH͕طఆͷಈ࡞ͩͬͨ ⾣ 4XJGU͔Β!OPFTDBQF͕طఆʹͳΔ // 明記がないものは、非エスケープなクロージャー func doSomething(predicate: () -> Int) { } // エスケープ可能にしたい場合は、明記が必要に func doSomething(predicate: @escaping () -> Int) { }
!OPFTDBQFΫϩʔδϟʔ
&TDBQJOHΫϩʔδϟʔʢ4XJGUͷطఆʣ
⾣ มΓͰɺࣗ༝ʹ֎࣋ͪग़ͤΔ
⾣ ෦ʹऔΓࠐΜͩมͷੜଘൣғ͕֦ு͞ΕΔ
func transfer(content: Data,
completionHandler: @escaping () -> Void) {
// 非同期処理など、別のスコープへ渡せる
DispatchQueue.main.async {
completionHandler()
}
}
!OPFTDBQFΫϩʔδϟʔ
/PO&TDBQFΫϩʔδϟʔʢ4XJGUͷطఆʣ
⾣ มΓͰɺ֎ʹ࣋ͪӡͳ͍
⾣ ఆٛͨ͠είʔϓ֎Ͱ͑ͳ͍͜ͱ͕ଋ͞ΕΔ
func transfer(content: Data,
completionHandler: () -> Void) {
// 非同期処理など、別のスコープへ持ち出せない
DispatchQueue.main.async {
completionHandler()
}
}
$MPTVSFVTFPGOPOFTDBQJOHQBSBNFUFS
bDPNQMFUJPO)BOEMFS`NBZBMMPXJUUPFTDBQF
!OPFTDBQFΫϩʔδϟʔ
/PO&TDBQFΫϩʔδϟʔͷར
⾣ ୈࡾऀʹอ࣋͞Εͳ͍͜ͱ͕ଋ͞ΕΔ
w Ή͠Ζɺ͕ؔࣗอ࣋͠ͳ͍͜ͱΛओுͰ͖Δ
w ؒҧͬͯͲ͔͜อ࣋ͯ͠͠·͏ͷΛ༧Ͱ͖Δ
⾣ ͲΜͳมΛғ͍ࠐΜͰ ॥ࢀর͕͜ىΒͳ͍
// たとえ、素性の知れない関数であっても …
func callBlackBox(predicate: () -> Int)
// @noescape なら循環参照の心配はない
callBlackBox {
return self.items.count
}
!OPFTDBQFΫϩʔδϟʔ /PO&TDBQFΫϩʔδϟʔͷੑ࣭ !OPFTDBQFͰ ΫϩʔδϟʔΛड͚औΔؔ ؔείʔϓ 変数 ғ͍ࠐΈ クロージャー 変数 !OPFTDBQF͠ Non-Escape クロージャー ֎ʹ࣋ͪग़͞Εͳ͍ !OPFTDBQFͳΒ ͨ͠ઌͰ ઈରʹ͍ऴΘΔ 変数 Ϋϩʔδϟʔͱม ऴྃ
!OPFTDBQFΫϩʔδϟʔ &TDBQJOHΫϩʔδϟʔͷੑ࣭ !FTDBQJOHͰ ΫϩʔδϟʔΛड͚औΔؔ ؔείʔϓ 変数 ғ͍ࠐΈ クロージャー 変数 !FTDBQJOH͠ Escaping クロージャー ֎ͷมʹอ࣋͞ΕΔ͔ !FTDBQJOHͩͱͨ͠ઌͰ ͍ऴΘΔͱ ݶΒͳ͍ 変数 Ϋϩʔδϟʔͱม ҡ࣋͞ΕΔ͔
!OPFTDBQFΫϩʔδϟʔ &TDBQJOH॥ࢀরʹҙ ؔείʔϓ ΦϒδΣΫτ obj: Object ғ͍ࠐΈ クロージャー obj !FTDBQJOHͰ ΫϩʔδϟʔΛड͚औΔϝιου Escaping クロージャー ϓϩύςΟʔʹอ࣋ ॥ࢀর プロパティー ॥ࢀরͰPCK͕ղ์͞Εͳ͍
!OPFTDBQFΫϩʔδϟʔ
&TDBQJOHʹΑΔ॥ࢀরͷྫ
class Object {
var completion: (() -> Void)?
func request(completion f: @escaping ()->Void) {
…; completion = f
}
}
let obj = Object()
// 循環参照を起こすか、外からはわかりづらい
obj.request {
print(obj)
}
4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ ද໘͔Β͜ͱ͍͘ʹ͑ݟΖΛத৺ʹհ
&OKPZ4XJGU 5IBOLZPV 4XJGUͰ৽͘͠ͳͬͨͱ͜Ζ &;/&5۽୩༑ IUUQF[OFUKQ ⾣ 4XJGUͷίϯηϓτ ⾣ "1*໋໊نଇͷओͳͱ͜Ζ ⾣ *NQMJDJUMZ6OXSBQQFE0QUJPOBM ⾣ 4FRVFODFͷ৽ػೳ ⾣ ΠϯσοΫε$PMMFDUJPO੍͕ޚ ⾣ !OPFTDBQFΫϩʔδϟʔ