Objective-C Programming Chapter 13 (Part 2)

Encoding
วิธีการที่ NSKeyedArchiver เปลี่ยนอ็อบเจ็กให้อยู่ในรูปของไบนารี่เรียกว่า encoding หรือการเข้ารหัส สิ่งที่เราต้องทำเพิ่มเติมคือเขียนเมธอด encodeWithCoder:  ซึ่งเป็นส่วนของแคทิกกอรี่ <NSCoding> และเราต้องเป็นผู้กำหนด key และข้อมูลในคลาสว่าจะถูกจัดเก็บด้วยรูปแบบใด โดยการใช้เมธอดของคลาส NSKeyedArchiver ที่เกี่ยวข้องกับการ encode เช่น

โปรแกรม ที่เราจะเขียนต่อไปนี้จะแสดงตัวอย่างการจัดเก็บอ็อบเจ็ก Product ที่เราได้เคยเขียนไป ให้สร้างโปรเจคขึ้นมาใหม่และใช้คลาส Product จากโปรแกรม 8.7 และเพิ่มแคทิกกอรี่ NSCoding ให้กับคลาส Product ซึ่งมีโค้ดดังนี้

โค้ดที่ได้เขียนไปคือทำการจัดเก็บ _name โดยใช้เมธอด encodeObject:forKey: และกำหนดค่าคีย์ให้เป็น ProductName และอ็อบเจ็กตัวท่ี่สองคือ _price จะถูกจัดเก็บด้วยเมธอด encodeFloat:forKey: ซึ่งมีค่าคีย์เป็น ProductPrice

Program 13.5

main.m

เมื่อให้โปรแกรมทำงานจะเห็นว่าโปรแกรมสามารถจัดเก็บคลาส Product ได้และไม่แสดง error เหมือนโปรแกรมทีผ่านมา

Decoding
หลังจากที่เราได้เข้ารหัสหรือ encoding ไปแล้ว เมื่อต้องการจะนำอ็อบเจ็กกลับมาใช้เราต้องใช้กระบวนการที่เรียกว่า decoding หรือการถอดรหัส ซึ่งเป็นกระบวนการย้อนกลับ สิ่งที่เราต้องทำเพิ่มเติมก็คือเขียนเมธอด initWithCoder: ซึ่งเมธอดนี้จะถูกเรียกใช้ทุกครั้งเมื่อมีการ unarchive อ็อบเจ็ก และเราจะนำอ็อบเจ็กกลับมาด้วยเมธอดที่เกี่ยวข้องกับการ decoding เช่น

ในการ decode อ็อบเจ็กเราต้องใช้ key ที่ตรงกันกับการ encode และใช้เมธอดให้ถูกต้องตามชนิดของตัวแปรที่ได้เข้ารหัสไป เราจะเขียนเมธอด initWithCoder ของคลาส Product เพื่อนำข้อมูลที่ได้เข้ารหัสไว้กลับคืนมา ซึ่งมีโค้ดดังนี้

ข้อดีอย่างหนึ่งของการใช้ archive คือเมื่อทำการ decode อ็อบเจ็กที่ได้กลับมาจะเป็นอ็อบเจ็กจากคลาสเดิม เช่น ถ้าเป็น NSMutableString ก็จะได้อ็อบเจ็กที่เป็นคลาส NSMutableString ดังเดิม เมื่อเขียนแคทิกกอรีเสร็จเรียบแล้ว ต่อไปก็เขียนส่วนของโปรแกม ซึ่งมีโค้ดดังนี้

Program 13.6

main.m

Program 13.6 Output
Apple 100.0

ผลลัพธ์ของโปรแกรมแสดงให้เห็นว่า อ็อบเจ็กที่เราได้จัดเก็บในโปรแกรม 13.5 นั้นได้ถูกนำกลับมาในโปรแกรม 13.6 ได้อย่างถูกต้อง

Custom Archives

ใน กรณีที่เราต้องการจะสร้าง archive เพื่อจัดเก็บข้อมูลในรูปแบบเฉพาะตามที่เราต้องการ เทคนิคหนึ่งที่นิยมใช้ในการจัดเก็บอ็อบเจ็กต่างๆให้รวมกันเป็นไฟล์เดียวคือ ใช้ NSData เนื่องจากคลาสนี้มีหน้าโดยตรงในการจัดการข้อมูลที่เป็นลักษณะไบนารี่ หลักการคร่าวๆคือ เราจะสร้างอ็อบเจ็กที่เป็น archiver ซึ่งทำหน้าที่เข้ารหัสอ็อบเจ็กต่างๆ หลังจากนั้นเราก็ย้ายข้อมูลจาก archiver มาไว้ยัง NSData นั่นเอง โปรแกรมตัวอย่างต่อไปนี้แสดงเทคนิคการสร้าง custom archive ด้วย NSData

Program 13.7

main.m

Program 13.7 Output
Write Success

เรา ได้ประกาศอาร์เรย์เพื่อใช้เก็บอ็อบเจ็ก iPad , iPhone และ Galaxy โดยแยกตามรายการของบริษัทที่ผลิตสินค้า จากนั้นสร้าง NSMutableData ขึ้นมาเพื่อใช้เป็นที่พักชั่วคราวของข้อมูลที่ต้องการจะจัดเก็บ ในบรรทัดที่ 28 ได้สร้างอ็อบเจ็ก archiver ด้วยการใช้เมธอด initForWritingWithMutableData: ซึ่งหมายถึงว่า archiver ที่สร้างขึ้นนี้เมื่อมีการ encode อ็อบเจ็กต่างๆ ข้อมูลจะถูกส่งต่อไปยังอ็อบเจ็ก data ในตอนนี้เรามีทุกอย่างพร้อมหมดแล้ว ก็เริ่มเข้ารหัสข้อมูลทีละตัวจนครบ หลังจากนั้นใช้เมธอด finishEncoding เพื่อบอกให้ archiver รู้ว่าไม่มีอ็อบเจ็กที่ต้องการจะเข้ารหัสแล้ว เมื่อทุกอย่างได้เข้ารหัสเรียบร้อยแล้ว ในบรรทัด 37 ก็ให้อ็อบเจ็ก data ทำหน้าที่เขียนไฟล์ข้อมูล

arch_data

หลัง จากที่เราได้เข้ารหัสอ็อบเจ็กไปแล้ว ต่อไปเราจะเขียนโปรแกรมขึ้นมาทดสอบว่าข้อมูลที่ได้เขียนไปนั้น สามารถถอดรหัสกลับคืนมาได้อย่างถูกต้อง ซึ่งโปรแกรมในการถอดข้อมูลก็ทำงานในลักษณะกลับกันกับโปรแกรม 13.7 นั่นเอง

Program 13.8

main.m

Program 13.8 Output

Apple: (
    “iPad 120.00”,
    “iPhone 100.00”
)
Samsung: (
    “Galaxy 80.00”
)

ใน ขั้นตอนแรกโหลดข้อมูลจากไฟล์มาไว้ยังอ็อบเจ็ก data จากนั้นสร้าง unarchiver ด้วยเมธอด initForReadingWithData เพื่อที่จะให้อ่านข้อมูลจาก data ที่กำหนด เมื่อทุกอย่างพร้อมแล้วก็เริ่ม decode อ็อบเจ็กที่เราได้จัดเก็บ และในขั้นตอนสุดท้ายก็จบด้วยการเรียกเมธอด finishDecoding
unarch_data

Copy Object with Archiver

ใน บทที่ผ่านมาเราได้เรียนรู้เกี่ยวกับการก็อปปี้ไปแล้ว ซึ่งปัญหาของการก็อปปี้อย่างหนึ่งคือ shallow copy ดังเช่นโปรแกรมที่ 12.3 การแก้ปัญหานี้ทำได้ด้วยการ deep copy ซึ่งต้องเขียนแคทิกกอรี่ <NSCopying> นอกจากวิธีการเขียนแคทิกกอรี่แล้วยังมีอีกวิธีคือใช้ archiver และ unarchiver และจากโปรแกรมที่ผ่านมาจะพบว่าทุกครั้งเมื่อทำการ unarchive จะได้อ็อบเจ็กขึ้นมาใหม่เสมอ โดยมีคุณสมบัติเหมือนกันทุกประการกับอ็อบเจ็กที่ได้จัดเก็บไว้ ดังนั้นแล้วเราจึงสามารถใช้วิธีการนี้เพื่อก็อบปี้อ็อบเจ็กในแบบ deep copy ได้เช่นเดียวกัน ดังเช่นตัวอย่างโปรแกรมต่อไปนี้

Program 13.9

main.m

Program 13.9 Output

Fruits: (
    Apple123,
    Mango,
    Orange
)
Other Fruits: (
    Apple,
    Mango,
    Orange
)

โปรแกรม 13.9 ดัดแปลงจากโปรแกรม 12.3 โดยโปรแกรมนี้สร้างอาร์เรย์ที่ประกอบไปด้วย Apple , Mango และ Orange จากนั้นในบรรทัดที่ 20 เราได้ใช้คลาสเมธอด archive อ็อบเจ็กที่ต้องการและเก็บไว้ที่ data นั่นหมายความว่าตอนนี้ ข้อมูลต่างๆของอ็อบเจ็ก fruits นั้นได้ถูกเก็บไว้ยัง data เรียบร้อยแล้ว ขั้นตอนต่อไปคือ unarchive อ็อบเจ็กกลับคืนมา ซึ่งจะได้อ็อบเจ็กใหม่ที่มีข้อมูลเหมือนกันทุกประการกับตัวต้นแบบ จากนั้นเราทดลองเพิ่มสตริง 123 ต่อท้าย ก็จะเห็นว่า Apple123 นั้นอยู่ในอาร์เรย์ fruits อย่างเดียว แยกขาดกันกับอาร์เรย์ otherFruits

บท นี้เราได้เรียนรู้ archiving และคลาสที่เกี่ยวข้องเช่น NSKeyedArchiver นอกจากนี้ยังมีคลาสที่มีชื่อและทำหน้าที่คล้ายกันนั่นคือคลาส NSArchiver ซึ่งเป็นคลาสที่เกิดขึ้นมาตั้งแต่ Mac OS 10.1 ในเวลาต่อมาคลาสนี้ก็ได้ถูกแทนที่ด้วย NSKeyedArchiver ใน Mac OS X 10.2 สิ่งที่แตกต่างกันระหว่างสองคลาสนี้คือ คลาส NSArchiver จะไม่สามารถกำหนด key ให้กับอ็อบเจ็กต่างๆได้ หรือพูดอีกอย่างว่าคลาสนี้จะเก็บอ็อบเจ็กได้เพียงตัวเดียวนั่นคือ root object ข้อเสียอีกอย่างของคลาสนี้คือไม่สามารถใช้กับ iOS ได้ อย่างไรก็ตามข้อดีของ NSArchiver คือไฟล์มีขนาดเล็กกว่า NSKeyedArchiver และทำงานได้เร็วกว่า

โหลดแบบ PDF ไปอ่าน Chapter 13
ส่วน Source code ก็นี่เลย Github

Leave a Reply