144 Views
October 16, 16
スライド概要
Swift の AnyObject の性質を、自分はすっかり見落としていたので、それについての基本的なところを確かめておくことにしました。Swift の @objc による動的ディスパッチ、けっこういい感じに出来たんですね。
※ Docswell での公開に移行する直前の Slideshare での閲覧数は 4,105 でした。
正統派趣味人プログラマー。プログラミングとは幼馴染です。
"OZ0CKFDU ͕ࣗݟམͱ͍ͯͨ͠ɺجຊͷ ΧδϡΞϧ4XJGUษڧձ PO &;/&5۽୩༑ IUUQF[OFUKQ 4XJGU
۽୩༑ 5PNPIJSP,VNBHBJ ⾣ 4XJGU͕ޠݴେ͖Ͱ͢ʂ ⾣ ΈΜͳͰָ͠Ήษڧձ͕େ͖Ͱ͢ʂ ⾣ ϓϩάϥϛϯάͷָ͠͞Λ͍͖͍͑ͯͨɻ !FT@LVNBHBJ UPNPIJSPLVNBHBJ $PEF1JFDFGPSNBD04 IUUQF[OFUKQ 9DPEFపఈղઆ
$PEF1JFDFGPSNBD04 ษڧձΛָ͠ΉΞϓϦ ⾣ ιʔείʔυΛ5XJUUFSͱ(JTUʹಉ࣌ߘ ⾣ ίʔυཝΛۭʹ͢Εɺී௨ʹπΠʔτՄೳ ⾣ ϋογϡλάΛઃఆͰ͖Δʗ͚Εͳ͍ #cswift
ษڧձΛ։࠵͍ͯ͠·͢ɻ Θ͍Θ͍ɺָ͘͠ɺ ΈΜͳͰޠΒ͑ΔॴΛࢦͯ͠ ԣJ1IPOF։ൃऀษڧձ ୈճ݄ͷ։࠵ ΧδϡΞϧ4XJGUษڧձ ୈճΛ݄ʹ։࠵ʢݕ౼தʣ ΈΜͳͰ4XJGU ෮शձ ୈճΛ݄தʹ։࠵ʢݕ౼தʣ ZJEFW ˏԣɾഅंಓ IUUQTBUOEPSHHSPVQTZJEFW DTXJGU !ԣɾ੨༿ IUUQTBUOEPSHHSPVQTDTXJGU NJOOB@EF@TXJGU ˏौ୩ IUUQDTXJGUDPOOQBTTDPN
NPPLNPPLSBEJP Ќ൛ ϜοΫϜοΫϥδΦ ۽୩ͱ៸໘͕ϓϩάϥϛϯάίʔυͷ͔Β ௌ͑ͯ͘͜ΔʹࣖΛָ͚ͯ͠ΉϥδΦ ຖ݄ୈ̎ɾୈ̐ ݄༵ ʹ৴ IUUQNPPLNPPLSBEJPDPNB ⾣ ୈ̑ ʢ݄ʹ৴༧ఆʣ ⾣ ୈ̐ ʰίϝϯτͷଓ͖ˍܕʱ ⾣ ୈ̏ ʰίϝϯτʱ ⾣ ୈ̎ ʰྻܕڍʱ ⾣ ୈ̍ ʰϓϩάϥϛϯάͱࢲͨͪʱ
ొஃ͚ͤͯ͞Δ͜ͱʹͳΓ·ͨ͠ɻ IUUQTFWFOUEPUTKQFWFOU
"OZ0CKFDU
ͦ͏͍͑"OZ0CKFDUͬͯɺ શͯͷΫϥε͕४͢ڌΔϓϩτίϧ ʜͩͱ͚ͩɺࢥ͍ͬͯͨɻ
४උࣝ r4XJGUr
४උࣝ ෆಛఆܕ "OZ ⾣ ҙͷܕͷΠϯελϯεΛද͖ͰݱΔ ⾣ ҙͷؔܕ·ؚΕΔ "OZ0CKFDU ⾣ ҙͷΫϥεܕͷΠϯελϯεΛද͖ͰݱΔ ⾣ ؔܕ!DPOWFOTJPO CMPDL ͳΫϩʔδϟʔΛ VOTBGF#JU$BTUͰΩϟετͨ͠߹͚ͩʹରԠ
४උࣝ ෆಛఆܕͷఆٛ "OZ ⾣ ΈࠐΈͷΩʔϫʔυͱͯ͠ఆٛ ⾣ 4XJGUͰUZQFBMJBT"OZQSPUPDPMͰఆٛ "OZ0CKFDU ⾣ !PCKDQSPUPDPM"OZ0CKFDUͱͯ͠ఆٛ
४උࣝ ෆಛఆܕͷ༻ ⾣ దͳʹܕΩϟετͯ͠͏ w JTԋࢉࢠɺBT BT ԋࢉࢠ w TXJUDIύλʔϯϚον switch instance { case 0 as Double: print("0 of Double") case let value as Int: print("\(value) of Int") case is Double: print("Double") }
४උࣝ r0CKFDUJWF$r
४උࣝ 0CKFDUJWF$Ϋϥε ⾣ .FTTBHF1BTTJOHํࣜ w ಈతσΟεύον ⾣ /40CKFDUΫϥεΛඞͣܧঝ w QFSGPSN4FMFDUPSܥϝιουৗඋ
"OZ0CKFDUͷ0CKFDUJWF$Ϋϥεͬͯɺ ࠷Ͱ/40CKFDUʹͯ͠QFSGPSN4FMFDUPS ʜ͢Δͷͩͱࢥ͍ͬͯͨɻ
%ZOBNJD%JTQBUDI r"OZ0CKFDUr
%ZOBNJD%JTQBUDI ֓ཁ ⾣ "OZ0CKFDUಈతσΟεύονΛαϙʔτ ⾣ !PCKDࢦఆͷػೳΛ࣮ߦͰ͖Δ let object = "Casual" as AnyObject let count: Int? = object.length let _: Void? = object.append?("Swift")
%ZOBNJD%JTQBUDI ϝιουͷ࣮ߦ ⾣ ௨ৗͱಉ͡ํ๏Ͱ࣮ߦ ⾣ σΟεύονՄೳ͔Ͳ͏͔ΛఆՄೳ // 通常通りに実行可能(メソッドは IUO 属性付き) let result: String = object.appending("Swift") // 通常は、メソッドに応じられない場合は強制終了 let result: String = object.appending("Swift") &YFDVUJPOXBTJOUFSSVQUFE SFBTPO&9$@#"%@*/4536$5*0/ // メソッドに ? をつけて、ディスパッチ可能性も判定 let result: String? = object.appending?("Swift")
%ZOBNJD%JTQBUDI ϓϩύςΟʔͷ࣮ߦ ⾣ ௨ৗͱಉ͡ํ๏Ͱ࣮ߦɺ0QUJPOBMܕ ⾣ σΟεύονͰ͖ͳ͚ΕOJM͕ฦΔ // 通常通りに実行可能、ただし戻り値は Optional 型 let count: Int? = object.length
%ZOBNJD%JTQBUDI rཹҙr
%ZOBNJD%JTQBUDIͷཹҙ
ܕ"OZ0CKFDUΛ໌ه
⾣ ΠϯελϯεΛ"OZ0CKFDUͰܕѻ͏
⾣ /40CKFDUͳܕΒQFSGPSNϝιουՄೳ
class MyClass : NSObject {
func myFunction(_ v: Int) -> Int {…}
}
let object = MyClass() as AnyObject
let result: Int? = object.myFunction?(10)
%ZOBNJD%JTQBUDIͷཹҙ
/40CKFDUͰѻ͏͜ͱՄೳ
⾣ /40CKFDUͰѻ͑QFSGPSN͕͑Δ
⾣ ҾΓ"OZ0CKFDUJWF$Ͱܥѻ͏
class MyClass : NSObject {
func myFunction(_ v: Any) -> NSNumber {…}
}
let object = MyClass() as NSObject
let result: Unmanaged<AnyObject>? =
object.perform(MyClass.myFunction(_:), with: 5)
let resultValue: Int? =
result?.takeRetainedValue().intValue
%ZOBNJD%JTQBUDIͷཹҙ
"OZ0CKFDU૬ʹܕඇରԠ
⾣ "OZ0CKFDUΛܧঝͨ͠ϓϩτίϧͰܕࡌهෆՄ
protocol MyClassProtocol : AnyObject {
}
class MyClass : NSObject, MyClassProtocol {
func myFunction(_ v: Int) -> Int {…}
}
let object = MyClass() as MyClassProtocol
let result: Int? = object.myFunction?(10)
WBMVFPGUZQF.Z$MBTT1SPUPDPMIBTOPNFNCFSNZ'VODUJPO
%ZOBNJD%JTQBUDIͷཹҙ
࣮ߦͰ͖Δͷ!PCKDͷΈ
⾣ !PCKDͰଘࡏ͠ͳ͍γάωνϟϏϧυΤϥʔ
⾣ ಉ໊ͷ!OPOPCKDػೳɺͼݺग़͞Εͳ͍
class Object : NSObject {
func method1() -> Int {…}
@nonobjc func method2() -> Int {…}
}
let object = Object() as AnyObject
let result1 = object.method1?()
let result2 = object.method2?()
// .some(x)
// .none
%ZOBNJD%JTQBUDIͷཹҙ !PCKDͷࢦఆํ๏ ⾣ /40CKFDUΫϥεΛܧঝ͢Δํ๏ ⾣ ରԠͨ͘͠ͳ͍ͷʹ!OPOPCKDΛ༩ // 原則、動的ディスパッチが可能 class Object : NSObject { func method1() -> Int {…} // 動的ディスパッチしたくないものに @nonobjc を付与 @nonobjc func method2() -> Int {…} }
%ZOBNJD%JTQBUDIͷཹҙ !PCKDͷࢦఆํ๏ ⾣ 4XJGUΫϥεͷػೳ͝ͱʹ!PCKDΛ༩͢Δํ๏ ⾣ !PCKDΛ͚ͳ͍ͷಈతσΟεύονෆՄ // 原則、動的ディスパッチは不可 class Object { func method1() -> Int {…} // 動的ディスパッチしたいものに @objc を付与 @objc func method2() -> Int {…} }
%ZOBNJD%JTQBUDIͷཹҙ !PCKDͷࢦఆํ๏ ⾣ ϓϩτίϧʹ!PCKDΛ༩͢Δํ๏ ⾣ ͦ͜Ͱنఆ͞Εͨͷɺ҉తʹ!PCKDͰ࣮ @objc protocol Protocol { func method() } class Object : Protocol { func method() {} }
%ZOBNJD%JTQBUDIͷཹҙ γάωνϟʔͷ໊લʹ͍ͭͯ ⾣ γάωνϟʔ໊4XJGU໊Λࢦఆ͢Δʁ ⾣ 0CKFDUJWF$໊Ͱࢦఆͨ͠ͷݕग़͞Εͳ͍ class Object { @objc(otherName) func originalName() {} } let object = Object() as AnyObject object.originalName?() // .some(()) object.otherName?() WBMVFPGUZQF"OZ0CKFDUIBTOPNFNCFSPUIFS/BNF
%ZOBNJD%JTQBUDIͷཹҙ γάωνϟʔͷ໊લʹ͍ͭͯ ⾣ γάωνϟʔ໊0CKFDUJWF$໊ࢦఆͰ͖Δʁ ⾣ Ͳ͔͜ʹಉ໊ͷఆ͕ٛ͋Εɺ྆ํͰ࣮ߦՄೳʁ class OtherClass { @objc func otherName() {} } class Object { @objc(otherName) func originalName() {} } let object = Object() as AnyObject object.originalName?() object.otherName?() // .some(()) // .some(())
%ZOBNJD%JTQBUDIͷཹҙ γάωνϟʔͷ໊લʹ͍ͭͯ ⾣ 0CKFDUJWF$໊͕͍ͨͷͱࠞࡏ͢Δͱᐆດʁ class OtherClass { @objc func originalName() {} @objc func otherName() {} } class Object { @objc(otherName) func originalName() {} } let object = Object() as AnyObject object.originalName?() object.otherName?() // ambiguous use of … // .some(())
%ZOBNJD%JTQBUDIͷཹҙ
ఆٛ͞Ε͍ͯͳ͍ػೳ
⾣ Ͳ͔͜Ͱ!PCKD͖Ͱఆٛ͞Ε͍ͯΔඞཁ͋Γ
⾣ Ͳ͜ʹଘࡏ͠ͳ͍γάωνϟϏϧυΤϥʔ
class MyClass : NSObject {
func myFunction(_ v: Int) -> Int {…}
}
let object = MyClass() as AnyObject
let result: Int? = object.xxxx?(10)
WBMVFPGUZQF"OZ0CKFDUIBTOPNFNCFSYYYY
%ZOBNJD%JTQBUDIͷཹҙ ఆٛॴͷҙ ⾣ ϩʔΧϧείʔϓͷ!PCKDγάωνϟʔ "OZ0CKFDUͷީิͱͯ͠ೝࣝ͞Εͳ͍ ⾣ Ͳ͔͜ʹಉ໊ͷ༗ޮͳγάωνϟʔ͕͋Ε ϩʔΧϧείʔϓͷ!PCKDػೳ࣮ߦͰ͖Δ func doSomething() { class Object: NSObject { // このシグネチャーは認識されない。動的実行は可 func someMethod() {} } }
"OZ0CKFDU͕ ͜Μͳੑ࣭ͩͬͨͳΜͯɺΒͳ͔ͬͨ ʜͦΜͳɺ͓Ͱͨ͠ɻ
&OKPZ4XJGU 5IBOLZPV "OZ0CKFDU ͕ࣗݟམͱ͍ͯͨ͠ɺجຊͷ &;/&5۽୩༑ IUUQF[OFUKQ ⾣ ४උࣝ ⾣ ಈతσΟεύον