http://2coders.com/protocol-oriented-programming/

[Basic] Use extension to help you implement a pure optional protocol in Swift

Kittisak Phetrungnapha
iTopStory
Published in
2 min readMay 28, 2017

--

ณ จุดๆ นี้ คิดว่า iOS Devs เกือบทุกคนน่าจะเขียน Swift กันหมดแล้ว ซึ่งทุกคนก็คงเคยทำ custom delegate pattern กันมาอยู่แล้วใช่ไหมล่ะ ที่มันเอาไว้ใช้สำหรับส่งค่าจาก class ปลายทาง กลับมายัง class ต้นทาง เมื่อ class ปลายทางทำงานใดๆ เสร็จสิ้นแล้ว ซึ่งจะเป็นความสัมพันธ์แบบ one to one ระหว่าง class ทั้งสอง ตัวอย่างง่ายๆ ก็เช่น

ซึ่งถ้าลองก้อปโค้ดไปรันใน playground ก็จะได้ผลลัพธ์ออกมาแบบนี้

MyClass2 is doing some task.............................MyClass2 has done its task.MyClass1 received a message from MyClass2.

ซึ่งก็โอเคตามปกติเนอะ ไม่มีอะไรแปลกแต่อย่างใด

แต่ถ้าสมมุติเราเห็นว่าไอ้เจ้า MyCustomDelegate เนี่ย มันสามารถนำไป reuse ใช้กับ class อื่นได้อย่างสมเหตุสมผลด้วย (ที่ต้องเน้นว่าสมเหตุสมผลเนี่ย เพราะว่าจริงๆ แล้ว เราควรสร้าง delegate แยกอีกอันมากกว่าที่จะ reuse เพราะมันเป็น one to one แต่เผื่อบางเคสจำเป็นต้อง reuse จริงๆ ก็จำเป็นต้องใช้เนอะ) โดยมีการทำงานมากขึ้น ทำให้เราต้องเพิ่ม function อันใหม่เข้าไป MyCustomDelegate อีกอันแบบนี้

protocol MyCustomDelegate: class {
func triggerTaskHasEnded()
func triggerAnotherTaskHasEnded()
}

ซึ่งปัญหาที่เกิดตามมาก็คือ

Type 'MyClass1' does not conform to protocol 'MyCustomDelegate'

ก็แน่ล่ะ protocol ใน Swift มันบังคับให้อะไรก็ตามที่ conform มัน ต้อง implement function ให้ครบด้วย ซึ่งแต่ก่อนถ้าเป็น Objective-C มันจะมี keyword @optional มาให้เราใช้ได้ ทำให้เลือก conform เฉพาะ function ที่จำเป็นต้องใช้จริงๆ ได้ ไม่เกิด boiler code มาก

ทีนี้เรามาทำ @optional กันใน Swift แบบ Objective-C กันบ้าง

@objc
protocol MyCustomDelegate: class {
func triggerTaskHasEnded()
@objc optional func triggerAnotherTaskHasEnded()
}

ก็โอเค โปรแกรมเราไม่ error แล้ว ได้ผลลัพธ์ออกมาถูกต้อง แต่ดูไม่ cool เลย ยังต้องใช้ keyword ของ Objective-C มาช่วยอีก มันจะมีวิธีที่ smart กว่านี้อีกไหมนะ

Protocol Extension

นี่เลยครับ เนื่องจากในภาษา Swift มี keyword extension ให้เราสามารถเพิ่ม function ให้กับอะไรก็ได้ ดังนั้นเราก็เอามาประยุกต์กับการทำ optional protocol ให้กับ MyCustomDelegate ของเราซะเลย ง่ายมาก แบบนี้

protocol MyCustomDelegate: class {
func triggerTaskHasEnded()
func triggerAnotherTaskHasEnded()
}
extension MyCustomDelegate {
func triggerAnotherTaskHasEnded() {}
}

เท่ากับว่าเรามี default implementation ของ function triggerAnotherTaskHasEnded() เรียบร้อยแล้ว ซึ่งเราก็ไม่จำเป็นต้องไป implement triggerAnotherTaskHasEnded() ใน MyClass1 อีกต่อไป เอาไว้ในอนาคตถ้าเราอยากจะใช้เมื่อไหร่ ก็ค่อยมา override อีกที ลด boiler code ไปได้อีก

ยังคงได้ผลลัพธ์การทำงานของโปรแกรมเหมือนเดิม

MyClass2 is doing some task.............................MyClass2 has done its task.MyClass1 received a message from MyClass2.

ก็ประมาณนี้แหละครับ หันมาใช้ pure Swift กันให้มากที่สุดเท่าที่จะทำได้กันดีกว่า (อาจจะเป็นความโรคจิตส่วนตัวของผู้เขียนก็เป็นได้) สำหรับวันนี้ก็ลากันไปเท่านี้ก่อน พบกันใหม่ บทความหน้า สวัสดีครับ :)

ติดตามเรื่องราวต่างๆ ทั้งเทคโนโลยี มุมมองชีวิต การเรียนรู้ การใช้ชีวิต ได้ที่ https://www.facebook.com/itopstory/

https://www.facebook.com/itopstory

--

--

Kittisak Phetrungnapha
iTopStory

I am a software engineer who fall in love to code, read, and write. :) itopstory.com