Property Wrappers จะมาช่วยให้เราเขียนได้เท่ขึ้นได้ยังไง 😎 ?
แถมยังทำให้ Code DRY มากขึ้นอีกด้วยนะ :)
เคยเห็นกันมามั้ย กับพวก @NSCopying, @Published, @State ต่างๆ ที่มันช่วยให้ property ของเรามีความสามารถเพิ่มเติมมา เทพซะเหลือเกิน 🤔
จากที่ต้องเขียน Observable ใน RxSwift พอมี เจ้า Combine มา กลายเป็นใช้ @Published ก็ช่วยให้ property มีความสามารถของ publisher ได้แล้ว
เดี๋ยววันนี้ ผมจะมาอธิบายให้ฟังถึง วิธีการใช้งาน ความสามารถของมัน แล้วก็ background ต่างๆ ว่ามันเกิดมาเพื่ออะไรกัน อยากให้ทุกคนได้ใช้กันเยอะๆ
มันดีจริงๆนะเนี้ย 😉
Property Wrappers คืออะไร ?
เจ้าตัว Property Wrapper เบื้องหลังการทำงานของมันคือ การสร้าง Layer อีกชั้นนึงขึ้นมา เพื่อไว้ใช้สำหรับเขียน Logic สำหรับการเก็บค่าของ property อีกที
ซึ่งข้อดีของมันคือ การที่เราสามารถย้ายโค้ดสำหรับการเก็บค่าของ property ไปไว้ตรงที่เจ้า Property Wrapper นี้ได้ !!
เผื่อว่ายังไม่เก็ต ขอยกตัวอย่างง่ายๆ อย่าง การทำให้ String ให้เป็น lowercase ทั้งหมด ถ้าเราเขียนแบบปกติก็ จะเป็นประมาณนี้
จะเห็นว่าการแปลงค่าให้เป็น lowercased ถ้าเรามี property ที่ต้องการใช้ logic แบบนี้ซ้ำๆกัน เราก็ต้องเรียก method lowercased ซึ่งถ้าหากว่ามันไม่ใช่ แค่ lowercased แต่เป็นอะไรที่ซับซ้อนขึ้นมา อย่าง Citizen Id หรือ Persistence ที่ต้องเก็บไว้ใน UserDefaults ต่างๆ ล่ะ ? Duplicate code แบบนี้คงไม่สนุกแน่
งั้นเราลองมาดู ถ้าเขียนเป็น Property Wrappers กันว่าจะหน้าตาเป็นยังไง
อย่างที่เห็นถึงแม้ว่าโค้ดจะยาวกว่าเดิมเล็กน้อย ฮ่าๆๆ แต่เราก็สามารถ ทำให้ Logic มัน centralized อยู่ที่ตัว Lowercase ได้
หลังจากนี้ ถ้าอยากให้ property ไหนเป็น lowercase เราก็แค่ @Lowercase ใส่ให้ ต้องบอกเลยว่า หล่อกว่าเดิม 100% 😎
วิธีใช้งานเจ้า Property Wrappers ล่ะ ใช้ยังไงง่ะ
เอาแหล่ะ มาดูแต่ละส่วนกันดีกว่า ว่าการจะใช้งาน Property Wrappers ต้องประกอบไปด้วยอะไรบ้าง ?
เจ้าตัว Property Wrapper เอง มันสามารถใช้ได้กับทั้ง Struct, Enumeration และ Class โดยมี property ที่ชื่อ wrappedValue ไว้ และกำหนด @propertyWrapper ไว้ก่อน class ที่เราต้องการใช้งาน แค่นี้ตัว class นั้นๆ ก็สามารถนำไปใช้งานเข้ากับ property ต่างๆได้แล้ว โดยใส่ @ชื่อ Property Wrapper เท่านั้นเอง
ถ้าเราตั้งเป็น @propertyWrapper struct OnlyOne {..}
เราก็เรียกใช้ Property Wrappers Only One ผ่าน @OnlyOne นั้นเอง
ขออธิบายเพิ่มอีกนิด ถึงการทำงานของมันว่ามันทำงานยังไงในมุม In depth ที่มากขึ้นนะ
เจ้าตัว Property Wrappers หลักการทำงานของมัน ตรงกับชื่อมันเป๊ะๆ เลย
คือการที่เรา wrap การทำงานของ property ไว้ ซึ่งในที่นี้ ที่นิยมทำกันก็คือ ไปคุม behavior ก่อนการ store หรือ get ค่าลงไป เพื่อให้เราสามารถ เขียน logic บางอย่าง ไว้ได้นั้นเอง
ถ้าเราแปลงตัว Lowercase ให้สามารถมองเห็นการทำงานง่ายๆ ของมัน เราจะได้เป็นตามภาพด้านล่างนี้
จากโค้ดด้านบนที่เราเห็น จริงๆเจ้าตัว Property Wrappers ไม่ได้ทำอะไรมาก นอกจากไปเป็น Layer อีกชั้นนึง ที่ครอบ property ที่เราต้องการจะใช้งาน ให้ไปเรียกผ่าน Struct, Class, Enumeration ที่เราต้องการก่อน โดยมี wrappedValue เป็นตัวรับค่า เท่านั้นเอง 😙
ลองใช้ PropertyWrapper กับ UserDefaults
ขอยกตัวอย่างที่ทุกคนน่าจะเห็นภาพกันง่ายๆ อีกสักตัวอย่าง ก่อนจะไปต่อ เพื่อให้ทุกคนเห็นภาพชัดเจน ว่าเราจะนำไปใช้อะไรได้บ้าง
โดยเราจะมาทำ propertyWrapper สำหรับ UserDefaults เพื่อผูกตัวแปร เข้ากับ UserDefaults โดยใช้แค่ Key และประเภทของตัวแปร เท่านั้น
ทีนี้ ถ้ามีตัวแปรไหนที่ต้องการใช้งาน UserDefaults เราก็ใช้ง่ายๆแค่
@UserDefault(key: th.co.creativeme.unicorn”)
var unicorn: String?
เท่านี้ ค่าก็จะถูก get และ set ผ่าน UserDefaults แล้ว !
อันนี้ตัวอย่างง่ายๆ บทความหน้า เดี๋ยวจะมาทำให้มัน SOLID + Secure มากขึ้น รอดูกันนะงับ 😝
Projected Value ส่วนเสริมหลักที่ขาดไม่ได้
ทีนี้ เพื่อนๆหลายคน ที่ดูคงยังสงสัยว่า ถ้ามันทำได้แค่นี้ แล้วพวก @Published ที่ข้างในมันมีความสามารถของพวก Observable ล่ะ มันทำได้ยังไง ?
เพราะที่ดูมา เหมือนจะยังไม่สามารถเขียนได้ หรือเขียนได้ยากมากๆ
จริงๆยังเหลือ พระรองอีกคนครับ ตัวนี้ก็ถือว่าเป็นหัวใจสำคัญที่ทำให้
Property Wrappers มีความสามารถโดดเด่นขึ้นมาอีกเพียบ!!
เจ้าสิ่งนี้เรียกว่า Projected Value มันจะช่วยให้เราสามารถ เข้าถึง property ได้หนึ่งตัว ใน Property Wrappers ได้ ซึ่งจริงๆ แค่ตัวเดียวมันก็เหมือนกับเป็นการ เปิดช่องกว้าง ให้เราสามารถเล่นอะไรกับมันได้อีกเยอะแล้ว
ยกตัวอย่างจากของ apple เองเลย ตาม gist นี้
จะเห็นว่า เรามี property ของเราสามารถใส่ dollar sign ($) ไว้ด้านหน้าได้ด้วย !!
เจ้าตัวนี้แหล่ะ คือ projectedValue
ตามตัวอย่าง เรามีตัวแปร someNumber ซึ่งใช้ @SmallNumber
และมี projectedValue ที่ไว้คอยเช็คว่า ค่าตัวเลขที่ใส่มานั้น มากกว่า 12 รึเปล่า
เราสามารถเข้าถึงได้ โดยใส่ dollar sign ($) ไว้ด้านหน้าชื่อตัวแปร
ก็จะเป็น $someNumber นั้นเอง ที่จะโยงไปหาค่า projectedValue
เท่านี้แหล่ะ โลกเปิดเลยครับ ฮ่าฮ่า เราสามารถ customize อะไรเพิ่มได้อีกมาก
อย่างตัว @Published เองก็ใช้ projectedValue เป็นตัว Observable อยู่ข้างในอีกที 😊
แถมๆ มันมีเหตุผลด้วยนะ ว่าทำไมถึงต้องใช้ dollar sign ($) เพื่อเป็นการแทนค่า projectedValue เพราะการใช้ $ จะไม่ทำให้ projectedValue มีชื่อตัวแปร ที่ชนกับตัวแปรทั่วไปได้ เพราะปกติ เราไม่สามารถใช้ $ ขึ้นต้นในการสร้างตัวแปรได้นั้นเอง :)
ก็ต้องขอจบ part 1 ไว้เท่านี้ก่อนนะฮะ เดี๋ยวต่อไป จะมาเล่าเกี่ยวกับ การใช้ Property Wrappers ในฉบับที่ advance ขึ้นมาอีกหน่อย เพื่อให้ทุกๆคน ได้เห็นถึง Use case ในการเอาไปใช้งานจริง ในมุมมองฉบับ Real life มากกว่านี้
ผิดถูกยังไง comment กันได้นะฮะ หรืออยากเสริมตรงไหนคุยกันได้เลย :)
มาเล่าวันนี้ เพราะยังไม่ค่อยเห็นเพื่อนๆคนไหน ใช้กัน ทั้งที่มันเป็นของดีมากๆ
ถ้าใครอ่านแล้วเข้าใจ นำไปใช้งานได้ ก็ทักมาบอกกันบ้างนะ เราจะดีใจมาก 😚