Posts tagged ‘Cocoa Touch Programming’

Objective-C Coding Style : Naming

“ภาษา” เป็นสิ่งที่ถูกประดิษฐ์ขึ้น เพื่อสื่อสารระหว่างกัน ภาษาไทย, ภาษาอังกฤษ, ภาษามือ, ภาษากาย ฯลฯ ล้วนแล้วแต่เป็นสิ่งที่ถูกประดิษฐ์ขึ้นเพื่อการสื่อสารทั้งสิ้น รวมทั้ง “ภาษาโปรแกรมมิ่ง” ก็คือสิ่งที่โปรแกรมเมอร์ใช้สื่อสารกับคอมพิวเตอร์เช่นเดียวกัน แต่นอกเหนือจากนั้น มันก็เป็นภาษาที่สื่อสารระหว่างโปรแกรมเมอร์เช่นเดียวกัน

สิ่งที่ผมเกริ่นมาข้างต้น คือความสำคัญของหัวเรื่องเรื่องนี้ เรื่อง Coding Style ของ Objective-C จริงๆเรื่องของ style มันเป็นของใครของมัน แต่ใน Entry นี้ผมขอโฟกัสกับ style ที่ “พึงกระทำด้วยประการทั้งปวง” การที่โค้ดของคุณอ่านง่ายเข้าใจง่ายไม่ซับซ้อน หรือที่ฝรั่งเรียกว่า “Clean Code” นั้น ช่วยเพิ่มประสิทธิภาพการทำงานเป็นทีม การลดเวลาการทำงานของคนที่มาทำงานต่อจากคุณ(เช่นการแก้บั๊ก) และง่ายต่อการ Optimize, Refactor หรือประโยชน์อื่นๆทั้งปวงในกระบวนการ Software Development

ใน Entry นี้ผมขอ Cover แค่เรื่อง “การตั้งชื่อ” ในการเขียน Code ภาษา Objective-C เท่านั้นนะครับ จริงๆเรื่องมันเล็กมาก มากจนผมไม่เคยคิดว่าจะมีคนทำด้วยซ้ำ แต่กระนั้น …ผมก็เจอกับตัวเองมาทุกเคส (จนต้องมาเขียนบลอกนี่แหละ) …แต่อย่างที่บอกว่าเรื่องของ Style เป็นเรื่องส่วนบุคคล มีแค่บางข้อเท่านั้นที่ผมอยากระบุเลยว่า “ควรทำตาม” แต่บางข้อก็ “แล้วแต่คุณ” ว่าแล้วก็ไปดูกันเลย

ใน Objective-C การตั้งชื่อตัวแปรโดยรูปแบบของคำ ควรเป็นลักษณะที่เรียกว่า “Camel Case” คือขึ้นต้นแต่ละคำในชื่อด้วยตัวพิมพ์ใหญ่ ส่วนตัวแรกจะเป็นพิมพ์ใหญ่ก็ต่อเมื่อเป็นชิื่อ Class เท่านั้น นอกนั้นขึ้นด้วยพิมพ์เล็กหมด เช่น MyClass, myAttribute, -(void)myFunctionWithParameter:(id)param เป็นต้น ข้อนี้จัดเป็นเรื่อง “พึงปฏิบัติตามด้วยประการทั้งปวง” แต่ข้อนี้ขอเพิ่มเติมว่า “เขียนภาษาไหนก็ตามแบบนั้นไป” ดีที่สุด

การตั้งชื่อตัวแปร หรือ attribute ของ Class ในภาษา Obj-C นั้น ถูกระบุในเอกสารของ apple อย่างชัดเจนว่า “ขึ้นต้นด้วยตัวพิมพ์เล็ก เสมอ!!” ใครที่กำลังติดนิสัยนี้อยู่ เปลี่ยนพฤติกรรมเถอะครับ เรื่องการตั้งชื่อเป็นเรื่องสามารถทำให้เกิดความเข้าใจผิดได้อย่างมากมาย เพราะการตั้งชื่อขึ้นต้นด้วยตัวพิมพ์ใหญ่ มันหมายถึง “ชื่อ Class” อันนี้เรื่องใหญ่ครับ ขอจัดความสำคัญอยู่ในระดับ “พึงปฏิบัติตามด้วยประการทั้งปวง”

ส่วนการตั้งชื่อโดยใช้ _(Underscore) ในการเติมด้านหน้าหรือต่อท้าย เป็นเรื่องที่ “ทำได้” ครับ เป็นการป้องกันการเรียกใช้ตัวแปรที่ชื่อซ้ำกันได้ เช่น tableView ที่เป็น attribute กับ tableView ที่เป็นค่าที่ return มาจาก delegate method หรืออาจใช้เพื่อระบุว่าเป็น class attribute เจาะจงว่าเป็น private class attribute แบบนี้ก็ยังโอเคครับ ไม่ผิดกฎอะไรใดๆ และเป็นที่ใช้กันอยู่ทั่วไป

เรื่องก้ำกึ่งอยู่เรื่องนึงเกี่ยวกับการตั้งชื่อคือเรื่องการ “ย่อ” เรื่องนี้อยากจะบอกถึงน้องๆที่เริ่มเขียนโปรแกรมลงไปเลยด้วยซ้ำ ว่า “อย่าติดนิสัยการตั้งชื่อโดยไม่สื่อความหมายเลยครับ” ไอ้ int a, bool b, char *c เนี่ย หยุดเถอะครับ โอเคว่ามันไม่ใช่กฎ แต่เรียกว่าเป็น “มารยาท” ก็แล้วกันครับ จะมียกเว้นไว้บ้างบางตัวก็ถ้าเป็น i แล้ววนลูป อันนี้เชื่อว่าเป็น de-facto (หมายถึงมาตรฐานที่รู้ๆกันทั่วไป) แต่ผมก็ใช้ idx มากกว่านะ อันนี้ก็แนะนำว่า ชื่อยาวนิด แต่สื่อความหมาย ดีกว่าสั้นกุดแต่ไม่รู้ห่าอะไรเลยครับ”

…นี่แหละครับ หลักๆของการตั้งชื่อในภาษา Objective-C แค่นี้เอง ง่ายมาก บางคนอาจไม่เข้าใจเพราะคุ้นกับภาษาอื่นมากกว่า เลยติดมา อันนี้ก็คงต้องปรับตัวให้เหมาะสมกับงานที่ทำและภาษาที่ใช้ไปนั่นแหละครับ ส่วนใครที่เริ่มหัดเขียนก็เริ่มฝึกให้ถูกต้องนะครับ

Entry นี้อาจจะดูเขียนแบบ “ใส่อารมณ์” เข้าไปบ้าง เพราะเจอกับตัวเองมาตรงๆทุกข้อ(เจอความลำบากในการแก้งานที่ตั้งชื่ออย่างมีปัญหา) ใครไม่พอใจก็ผ่านไปนะครับ อย่าว่ากัน สำหรับ Entry นี้ ขอจบแต่เท่านี้ครับ Happy clean coding ครับ :)

สิงหาคม 17, 2011 at 4:33 pm 2 ของความคิดเห็น

Magic of NSLog

การ Log ที่ดี ก็มีผลให้การทำงานเราสะดวกรวดเร็วขึ้นนะครับ แน่นอน การใส่สัญลักษณ์ไว้ใน Log ก็เป็นวิธีการแบบลูกทุ่งๆอย่างนึงที่ใช้ง่ายและได้ผล แต่เยอะๆเข้าแทนที่จะช่วยให้เร็วขึ้นมันจะเป็นตรงกันข้าม เพราะลายตากับ Log ไปหมด หรือจะให้ระบุรายละเอียดกันทุกบรรทัด ก็เสียเวลาเกินไป ใน Entry นี้ ผมเอา Trick การ Log ให้มีประสิทธิภาพมากขึ้นมาฝากครับ

Trick #1 : รู้รึเปล่า ว่าการทำงานพร้อมกับการ Log ค่าไปด้วย ทำให้เป็นการลดประสิทธิภาพการทำงานของ App ลงไปเยอะเลย ก่อน  Submit app ขึ้น App store เราควรจะ remove log ของเราออกไปด้วย …จริงอยู่ว่า App ทั่วไปอาจไม่มีผลต่อประสิทธิภาพโดยนัย แต่ถ้าเป็นเกม …มีนัยครับ ดังนั้น เราจะสร้าง Log ของเราเองขึ้นมา ที่ให้ Log ค่า ตอนที่ XCode ตั้งค่าเป็น Debug mode เท่านั้น ใส่โค้ดพวกนี้ในไฟล์ xxx_Prefix.pch ของโปรเจค เพื่อให้มีผลกับทั้งโปรเจคครับ

#ifdef DEBUG
# define JELog(fmt,...) NSLog(@"%@",[NSString stringWithFormat:(fmt), ##__VA_ARGS__]);
#else
# define JELog(...)
#endif

อธิบายโค้ดดังกล่าวได้ว่า เราสร้าง JELog ขึ้นมาเพื่อให้มันทำงานเหมือน NSLog เลย แต่จะพิมพ์ออกทางหน้าจอเมื่อ Preprocessor Macro ถูกเซตคำว่า DEBUG เอาไว้ แต่ถ้าไม่ได้เซตก็ไม่ต้องทำอะไร

ส่วนการเซตค่า  Preprocessor Macro ไปเลือกที่ Project->Edit Project Settings เลือก Debug ในช่อง Configuration และใส่ค่า DEBUG (หรือคำอื่นๆที่นิยามไว้) ใน Preprocessor Macro เซคชั่น GCC 4.2 – Preprocessing

…แค่นี้แหละครับ เสร็จแล้ว คราวนี้เรา Build ในโหมด Release ก็ไม่มี Log มาบั่นทอนประสิทธิภาพ App เราแล้ว

Trick #2: จะดีแค่ไหน ถ้าการ Log ทำให้เรารู้ได้ว่า มันโดน Log มาจาก Function อะไร และบรรทัดไหน เราสามารถเพิ่มมันได้เอง ในรูปแบบที่เราต้องการ และไม่ต้องเหนื่อยมาใส่แบบลูกทุ่งทีละบรรทัดทีละ Log ด้วย ทำได้ง่ายๆแบบนี้ครับ

#define JELog(fmt,...) NSLog((@"%s-%d:" fmt),__PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

เพียงเท่านี้ เราก็ Log สิ่งที่เราต้องการพร้อมชื่อ Function และบรรทัดนั้นได้ง่ายๆแล้วครับ นอกจากนี้ยังมี __FILE__ เพื่อ log ชื่อไฟล์ชื่อนั้นอีก แต่ผมไม่ใส่เพราะผมไม่ใช้ อิอิ

ครับ สำหรับ Entry นี้ก็คงกล่าวถึงแค่นี้ ส่วนถ้าใครยังไม่สะใจอยากแต่งอยากเติมอีก ก็เข้าไปดูในเครดิตครับ มีคนทำไว้หลายแบบเหมือนกันสำหรับผม แค่นี้ก็สบายแล้ว หุหุ …ว่าแล้วก็จบเท่านี้ดีกว่า Happy Logging นะครับ ;)

Credits:

@memogames
iphoneprogrammingfordummies.blogspot.com
Stack Overflow : NSLog Tip & Trick

มีนาคม 24, 2011 at 5:23 pm ใส่ความเห็น

How to make XCode 3 with iOS SDK4 can build iOS SDK3.1.x

จาก Entry ก่อนๆหน้านี้ทีเคยบ่นๆไปเรื่องที่ XCode3 ตัวล่าสุด จะมาพร้อมกับ iOS ตั้งแต่เวอร์ชั่น 3.2 ขึ้นไป ผลก็คือ เราไม่สามารถ test application ของเราได้ว่า มันรันบน iOS3 ได้มั้ย

แอปเปิลคงตั้งใจจะดัน iOS4 เป็นมาตรฐานของ iPhone App แต่ในความเป็นจริง มาตรฐานการใช้งานมันอยู่ที่ “เครื่องมัน Jailbreak ได้ถึงเวอร์ชั่นไหนแล้ว” ดังนั้นสำหรับผู้พัฒนาบางทีก็ต้อง test กับ iOS เก่าๆซักนิดอย่าง iOS3 ด้วย Entry นี้จึงนำเสนอวิธีการ “ทำให้ XCode with iOS4 สามารถ Build กับ iOS3 ได้ด้วย!! ” เริ่มกันเลยครับ

สิ่งที่ต้องการ

1. iPhone SDK with iOS3 และ iOS4 ที่ติดตั้งกันแบบแยกโฟลเดอร์

วิธีการติดตั้งแบบแยกโฟลเดอร์ จะเปลี่ยนตอนเลือก Destination หรือติดไปก่อน เสร็จแล้วค่อยสร้าง folder ไว้อันนึงแล้วลากมาใส่จาก folder Developer แบบดิบๆเลยก็ได้ครับ

2. Terminal หาไม่ยากเลยครับ เครื่องมันมีมาแล้ว

วิธีการที่จะทำก็คือ สร้าง Symbolic link (หรือที่ในวินโดวส์เรียกว่า Shortcut) ที่ XCode จะทำการค้นหา Library ของ iOS3.x ลงไป ซึ่งก็จะอ้างอิงจาก iPhone SDK with iOS3 นั่นแหละครับ ขั้นตอนมีดังนี้

ผมขอแทน ${SDK3} = path ของ iOS3 SDK และ ${SDK4} = path ของ iOS4 SDK นะครับ

จากนั้นเปิด Terminal ขึ้นมา จากนั้น พิมพ์คำสั่งดังนี้

sudo ln -s ${SDK3}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.?.sdk ${SDK4}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.?.sdk

จากนั้นใส่ password ของเครื่อง หลังจากนั้นเมื่อเปิด XCode ขึ้นมาใหม่ จะพบว่ามี Library ของ iOS3.1.? แล้วครับ ง่ายมากๆ

แต่อย่างไรก็ตาม วิธีการนี้ “ใช้ได้กับ Device เท่านั้นนะครับ Simulator ไม่ได้” เพราะ Simulator เป็น Simulator ที่ลง iOS4 อยู่แล้วครับ (หรือจะมีใครเขียน Script ให้เลือก simulator ตอน จะ run บน simulator ได้ก็แบ่งผมมั่งนะครับ อิอิ)

Entry นี้ก็ขอจบแต่เพียงเท่านี้ครับ หวังว่าจะมีความสุขจากการทำแอพ 2 เวอร์ชั่นโดยไม่ตัองสลับ XCode แล้ว …Happy XCoding ครับ :D

สิงหาคม 8, 2010 at 1:57 am 2 ของความคิดเห็น

Why I choose XCode4 Even it still preview ?

ห่างหายไปนานกับการเขียน Blog เกี่ยวกับ iPhone Development ของผม ตอนนี้ต้องเปลี่ยนเป็น iOS Development แล้วละมั้ง ถึงจะถูก เพราะ iPhone ได้เลื่อนสภาพกลายเป็น Platform อีก 1 Platform ของ Apple ไปเป็นที่เรียบร้อยแล้ว

เกี่ยวกับ Entry นี้ หัวข้อก็คงบอกได้ชัดเจนว่าจะเขียนถึงเรื่องอะไร? ใช่แล้ว !! XCode4 นั่นเอง

เพิ่งเปิดให้ Download ไปลองใช้กันสดร้อนๆ แค่วันสองวันที่ผ่านมา(จากวันที่เขียน Entry นี้นี่เอง) หลังจากที่ได้เห็นการ Demo ในวิดีโอของงาน WWDC’10 เชื่อว่าหลายคนน้ำลายหก อยากลองของเล่นตัวนี้กันแน่นอน ส่วนตัวผมได้ลองมาตั้งแต่ Preview 1 แล้ว (เวอร์ชั่นที่แจกในงาน) บั๊กเยอะมาก มากจนไม่สามารถเอามาทำเป็นงานหลักได้ ก่อนหน้านี้ ผมจึงไม่ Review อะไรใดๆเกี่ยวกับการใช้ XCode4

ส่วนตัว Preview 2 ที่ออกมาให้ Download นั้นแก้บั๊กต่างๆไปเยอะแล้ว แต่เวอร์ชั่น Preview ก็คือ Preview ไม่มีทางสมบูรณ์และราบรื่นได้เหมือนตัวเต็ม และไหนจะเรื่อง Learning Curve ที่คงจะค่อนข้างสูงแน่นอน เพราะความต่างระหว่าง XCode3 และ 4 นับว่าต่างกันจนไปแทบไม่เป็น

ว่ากันตามตรง ถ้าอยากให้งานเสร็จเร็ว ใช้ XCode3 ไปก่อนดีกว่าครับ สาเหตุหรือปัญหาต่างๆที่ยังเจอใน XCode4 Preview 2 มีมากมายเอาเรื่อง ตั้งแต่

  • ปัญหาเรื่อง Key ลัด – กับ User ไม่น่ามีปัญหา แต่กับ Programmer ผมเชื่อว่าไม่ใช่ และเป็นเรื่องใหญ่ซะด้วย Key ลัดต่างๆที่ใช้อยู่บ่อยๆ ใน XCode3 เช่น Toggle ระหว่าง .h กับ .m (cmd+shift+up arrow) หรือสุดยอดคีย์ลัดขาประจำอย่าง Comment (cmd+/) มันหายไปครับ ยังไม่สามารถใช้ได้ใน version นี้
  • ปัญหาเรื่อง Code Sense, Auto Complete – ยังไม่ฉลาดเท่าที่ควร ผมเชื่อว่าการที่คุณกด nsl แล้วกด esc คุณหวังว่า กด Enter แล้วจะได้ NSLog มาใช้ เสียใจครับ คุณจะได้ NSLock มาใช้แทน นอกจากนั้น Snippet ต่างๆที่เราคาดหวังว่าจะขึ้นมาอย่างรวดเร็วอย่าง if (กด if แล้วกด esc จะได้ snippet มาใช้ได้ทันที) ก็จะยังไม่มีอีกเช่นกัน ถึงจะสามารถเพิ่มเองได้อย่างไม่ยากอีกต่างไป (แถมเท่อีกตะหาก เพิ่มใน IB) แต่เชื่อว่า คุณไม่อยากนั่งเพิ่มอะไรที่เคยใช้ได้โดยไม่ต้องมานั่งกรอกเองหรอก
  • ปัญหาเรื่อง Speed – ถ้าใครใช้ Mac รุ่นเก่าประมาณ 2-3 ปีลงไป ทำใจนะครับ เล็งหาเครื่องใหม่กันเถอะ (ผมด้วย) เพราะกิน Resource เอาเรื่องเลย อาจจะไม่ถึงกับรันไม่ได้ แต่การทำงานก็ไม่ลื่นปรื๊ดปร๊าดเหมือนใน XCode3 แน่นอน ตัวอย่างเช่น ตอนลาก Outlet ใน IB ไปลงใน Code ใน Demo มันดูน่าประทับใจมาก แต่ในโลกแห่งความเป็นจริง(ของเครื่องเก่าๆ) มันงดงามดังวิดีโอซักเท่าไหร่ วิธีที่พอจะช่วยได้บ้างก็คงเป็นการปิด Safari ที่เปิด tab ไว้เยอะๆ ละมั้งครับ คงพอช่วยได้
  • บั๊กจุกจิกเล็กน้อยที่จะฟ้องขึ้นมาเรื่อยๆ ให้ได้รำคาญเป็นระยะๆเวลาทำอะไร ท่องไว้ละกันครับ ว่า..มัน..pre..view

จากข้างต้น จะเห็นได้ว่าบั๊กมันไม่น้อยเลย แต่บอกเลยว่าไม่ใช่ไม่ดีนะครับ มันดีมากๆ แต่ยังไม่สมบูรณ์เท่านั้นเอง ถึงอย่างนั้น ผมเองก็ยังดึงดันจะใช้ XCode4 ไปเลย แทนที่จะใช้ XCode3 อย่างที่บอกผู้อ่าน …เพราะอะไร?

…เพราะ XCode3 with iOS SDK3 กับ XCode3 with iOS SDK4 มันทำงานไม่เข้ากันน่ะสิครับ ถ้าคุณต้องเขียน App ที่ support ทั้ง SDK3 และ SDK4 เป็นเรื่องน่าตลกปนเศร้าที่เราต้องลง SDK ถึง 2 ตัว เพราะ SDK4 ไม่มี Lib iOS3 (ไม่นับ 3.2 ที่เป็น iPad) และ SDK3 ไม่มี lib iOS4 สาเหตุที่ต้องแยกกันแบบนี้ เชื่อว่าเป็นเพราะ Simulator + ต้องการ Force ให้ Programmer พัฒนา App base เป็น SDK4 ทั้งหมด

หารู้ไม่ว่าในหมู่ผู้ใช้ Base ของ iOS version มันขึ้นกับว่า “Jailbreak ได้ถึงเวอร์ชั่นไหนแล้ว” และผมก็ต้องอิง Base นั้นซะด้วย

แม้ว่าผมจะต้องยอมเสีย พื้นที่ HDD และ Ram ให้กับ XCode 2 ตัวพร้อมกัน แต่ก็ไม่ได้หมายความว่า “ปัญหามันจะไม่มี” ปัญหาที่ว่า เช่น

  • Simulator มึน – อย่างที่บอกไปข้างต้น ว่า Simulator น่าจะเป็นสาเหตุนึง เพราะเมื่อ Launch Simulator ที่เป็น iOS3 แล้ว จะรัน Simulator ที่เป็น 4 ซ้ำไม่ได้ เพราะมันมองว่าเป็น Process เดียวกัน แล้วถึงแม้ว่า จะปิดตัวที่ Launch อยู่ มันก็จะยังมึนและมองว่า Simulator ยังถูก Launch อยู่ วิธีแก้ไขที่ผมพบคือ “ปิด XCode แล้วเปิดใหม่” ก็พอแก้ไขได้ แต่คุณอยากเปิดๆปิดๆ XCode อยู่เรื่อยๆมั้ยล่ะ (วิธีการ Kill Process ก็น่าจะช่วยได้ แต่มันก็ยุ่งยากมานั่ง Kill ทุกครั้งอีกนั่นแหละ)
  • Developer Bundle ID ค้าง – อันนี้คงเป็นปัญหาใน XCode3 SDK iOS4 ถ้าคุณเปิด Project ด้วย iOS SDK4 จากนั้น Copy Source ของต้วเองไปวางที่เครื่องอื่น ผลคือ มันจะ Compile ไม่ได้ เพราะเครื่องอื่นจะไม่มี private key ของเครื่องก่อนหน้านั้น ถึงจะเปลี่ยนไปใช้ของเครื่องใหม่ก็ยังค้างและถามถึง private key ของเครื่องเก่าอยู่ (ผมโดนอันนี้เข้าไป เกือบส่งงานไม่ได้) วิธีการแก้ไข มี 2 แบบ คือ 1. Export private key ของเราไปลงเครื่องที่จะใช้โค้ดนั้น ถ้าไม่ได้ซีเรียสว่าจะโดนเอาไปใช้เรื่องไม่ดีก็ใช้ทำได้ หรือ 2. ดิบๆเลย Create Project ใหม่แล้ว Copy Source ไปวาง
  • IB เน่า – อันนี้ไม่แน่ใจว่าเฉพาะผมคนเดียวหรือเปล่า แต่ไฟล์ .xib ตัวเดียวกัน แต่เปิดจาก iOS SDK3 แล้วสลับไป iOS SDK4 “File Owner จะไม่เจอ Action/Outlet ที่กำหนดไว้ใน Class เลย แต่ App ยัง Launch ได้อยู่แค่จะเพิ่มอะไรลงไปไม่ได้เท่านั้นเอง วิธีก็เหมือนแก้ปัญหา Simulator ครับ Restart XCode

ที่หนักๆเลยก็คงเป็นปัญหาพวกนี้ครับ เพราะผมไม่รู้ต้อง Restart XCode อีกซักกี่ครั้ง ดังนั้น ผมขอไปเจอบั๊กของ XCode4 ดีกว่าครับ สำหรับใครที่พัฒนาโดยไม่ได้ซีเรียสเรื่องต้อง Support 3 และ 4 ด้วยก็ไม่ต้องตกใจกับ Bug ต่างๆที่เขียนไว้นะครับ มันเป็นบั๊กที่ผมเจอในการทำงานร่วมกันของ XCode พร้อมกัน 2 ตัวเท่านั้น เชื่อว่าถ้าใช้แค่ตัวเดียวก็คงไม่เกิดปัญหาเหล่านี้

สำหรับ Entry นี้ก็คงจบไว้แค่นี้ครับ คิดว่าคงจะมีเรื่องให้เขียนต่อๆไปอีกเยอะแน่นอน

…Happy XCoding ครับ

กรกฎาคม 28, 2010 at 3:40 pm ใส่ความเห็น

iPhone’s project multi-target programming

ท่ามกลางสถานการณ์บ้านเมืองรุนแรงอย่างนี้ อัพบลอกดีกว่า (เอ๊ะ ไม่เกี่ยว) บลอก Entry นี้จริงๆควรจะอัพขึ้นไปตั้งแต่อาทิตย์ที่แล้ว แต่ด้วยเหตุผิดพลาดบางประการ ที่พิมพ์ไปเสร็จแล้วพออัพขึ้น ที่พิมพ์ไว้ดันหายไปไหนหมดก็ไม่รู้ จากนั้นก็ต้องมานั่งบิ๊วอารมณ์กันใหม่อีกรอบ บัดนี้ก็ถึงเวลาเขียนอีกรอบแล้ว

ในการพัฒนา App ไม่ว่าจะบน Mac หรือ iPhone ก็ตาม คงจะเคยเห็นกันว่าบาง App มีหลายเวอร์ชัน เช่น Lite, Standard, Full, Pro, etc.. ซึ่งความแตกต่างส่วนมากก็มักจะเป็นเรื่องของการจำกัด Feature หรือ App บางตัวที่อยู่บน Platform Mac ก็มาอยู่บน iPhone ต่อ อย่างเช่นเกม plant vs zombie หรือ twitter client อย่าง echofon เป็นต้น

ถ้าถามหลายๆคนถึงวิธีการ Develop App พวกนี้ให้เป็นหลายๆเวอร์ชั่นดังกล่าว หลายๆคนอาจจะใช้วิธีการ Duplicate project โดยการ Copy file ทั้งโปรเจคมา แล้วเข้าไปแก้โค้ด ตัด feature ไปตามเวอร์ชั่นๆไป (ดูไม่ make sense เท่าไหร่ แต่ผมเชื่อว่ามี และเยอะด้วยที่ทำแบบนี้) ผมเองก็เคยเช่นกันครับ ทำ App 8 เวอร์ชั่นเลยทีเดียว(จริงๆก็ไม่ได้เห็นด้วย แต่เขาสั่งมาก็ต้องทำ) ปัญหาที่เจออย่างหนักหน่วงเลยก็คือ “การแก้ไข Bug ยุ่งยากและเสียเวลาเป็นที่สุด” เพราะบั๊ก 1 จุดต้องใช้เวลาเพิ่มเป็น 8 เท่าและความแน่นอนว่าการแก้แบบเดียวกันกับโปรเจคเวอร์ชั่นต่างๆกัน มันอาจใช้ไม่ได้ผลซะด้วย

ดังนั้นการทำ App หลายๆเวอร์ชั่นด้วยวิธีการ Duplicate project ไม่น่าจะเป็นทางเลือกที่ควรนัก สำหรับการทำโปรเจคหลายๆเวอร์ชั่น โดยเฉพาะตอนที่ iPad มันเริ่มเข้ามาแล้วอย่างเช่นตอนนี้ ตามจริงมันก็ไม่ควรเป็นแบบนั้นอีกเช่นกัน ในเมื่อ XCode มี Target ให้ใช้อยู่ แล้วทำไมเราถึงไม่ใช้มันล่ะ

Target คืออะไร? Target เปรียบเสมือนพิมพ์เขียวที่กำหนดค่าต่างๆในขั้นตอนการ build ผลก็คือ เราสามารถกำหนดได้ว่าตั้งแต่ target ไหนชื่ออะไร ใช้ไอค่อนตัวไหน ไฟล์ไหนบ้างที่จำเป็นต่อการ build ยันรูปแบบผลที่ได้ว่าต้องการเป็น Application หรือ static library

เวลาเรา Create project ขึ้นมาซักตัว Target จะมีมาให้โดยปรกติเลย 1 ตัว ซึ่งจะอยู่ใน Section Targets ซึ่งเราสามารถเพิ่มได้ตอนไหนก็ได้ โดยการไปที่ Menu Project > New Target… จากนั้นจะขึ้น Window ขึ้นมาให้เลือก Target แบบที่เราต้องการ จากนั้นก็ตั้งชื่อ Target ที่สร้างขึ้น กด Finished ก็เป็นอันเสร็จเรียบร้อย (ตอนนี้เรากำหนดรูปแบบได้แล้ว)

ผลที่ได้จะได้ Target อันใหม่มา 1 อันและ Plist สำหรับ Target นั้นอีก 1 ไฟล์ Plist ก็เป็นที่รู้กันว่าไว้สำหรับการตั้งค่าต่างๆเช่น icon, bundle id, bundle name, etc… ซึ่งเราก็สามารถกำหนดได้ตามต้องการ Target ตัวใหม่ก็เช่นกันเราสามารถกำหนด Framework ที่ใช้ product name, platform ของ Application, etc… ตั้งค่าได้ทั้งหมดราวกับว่ามันเป็นคนละโปรเจคนั่นแหละครับ

องค์ประกอบของ Target ก็มีต่างกันไป ใน Entry นี้ขอพูดถึงแต่แบบ Application เท่านั้นนะครับ Application จะประกอบด้วย 3 ส่วนคือ

component.png

  1. Copy Bundle Resources – เป็นส่วนของ Resource ต่างๆใน Project พวก รูปภาพ, ไฟล์เสียง, วิดีโอ, ฯลฯ
  2. Compile Sources – เป็น Source code ล้วนๆครับ เอาแต่ไฟล์ .m เท่านั้น แล้วก็สำหรับ project จะต้องมี main.m ด้วยนะครับ อย่าลืม ไม่งั้น App จะรันไม่ได้นะครับ สำคัญมาก!!
  3. Link Binary With Libraries – เป็น Framework ที่ใช้ร่วมครับ ปรกติก็จะมี UIKit.framework ตัวนึงละ (สำหรับ iPhone/iPad) หรือไม่ก็ Cocoa.framework (สำหรับ Mac App)

วิธีการก็คือ Target ไหนใช้อะไร Compile บ้างก็ลากใส่เข้าไปตามหมวดหมู่ที่บอกข้างต้นครับ ไม่มีอะไรมาก หรือเวลาที่เรา Add ไฟล์อะไรก็ตามเข้ามาใน Project จะมี Sheet ขึ้นมาถามเราว่า ไฟล์นั้นจะ Copy หรือไม่ จะ link กับ Project อะไรยังไง ก็ให้ลองสังเกตด้านล่างครับ ว่าจะมีถาม Target ไหนด้วย เราก็สามารถเพิ่ม Resource ให้กับแต่ละ Target ผ่านทางนี้ได้เช่นกัน

addtoproj.png

อันนี้เป็นผลพลอยได้ของการสร้าง Target ตั้งแต่แรกๆครับ ส่วนถ้าไม่ได้ทำไว้แต่แรกก็ต้องมาลกาเพิ่มเอาเอง หรืออีกวิธีนึงคือ Duplicate target เอาแล้วค่อยเพิ่ม/ตัดออก เอาก็ยังได้ แต่วิธีนี้ต้อง config อะไรเยอะหน่อยเพื่อไม่ให้มันทับกัน และผมจะไม่ขอพูดถึงในที่นี้นะครับ มันค่อนข้างเยอะ

ต่อไปเป็นวิธีการเลือก Target วิธีการไม่ยากเลย กำหนดเอาที่ปุ่มด้านซ้ายบน กดแล้วจะขึ้น Menu ขึ้นมา ก็เลือก Target ที่ต้องการ build แค่นี้แหละครับ เสร็จแล้ว ง่ายจัง

settarget.png

เราได้ Target ใหม่แล้วสามารถ Config ได้ตามต้องการ คราวนี้เราจะสามารถใช้ source code เดียวกันแต่กำหนดการทำงานให้ต่างกันตาม target ได้หรือไม่ เพราะไม่งั้นการสร้าง target ก็ไม่มีประโยชน์อะไรเท่าไหร่ เพราะต้องเขียน class มากกว่ารอบเดียวขึ้นไปอยู่ดี ? คำตอบคือ “ได้ครับ” วิธีการที่ผมใช้ก็คือ “การตั้ง Tag ให้ Target แล้วเขียน source code กำหนดไปแต่ละ target โดยดูค่าจาก tag นั่นแหละ” (งงมั้ยเนี่ย)

ขั้นตอนก็คือ ไปตั้ง Tag ให้ Target โดยการ Double click ที่ target ที่ต้องการตั้ง tag (ขอเรียกแบบนี้แล้วกัน) ไปที่ Tab build แล้ว search Setting ว่า Other C Flags (อยู่ใน GCC 4.2 Language ครับ) ตั้งค่าเป็น “-DTARGET_NAME=1” ค่าหลังเครื่องหมาย = ก็แล้วแต่จะตั้งนะครับ

targetname.png

จากนั้นในส่วนของ Source code ที่ต้องการให้มีความแตกต่างในแต่ละ Target ก็จะใช้คำสั่ง #if เข้ามาช่วยครับ คำสั่งนี้จะเป็น if ในระดับของการ build เท่านั้น ไม่เกี่ยวกับ application logic ครับ ตัวอย่างการโค้ดก็เป็นแบบนี้

// Implement for each target

#if TARGET_NAME == 1
[aButton setHidden:NO];
[bButton setHidden:NO];
#elif TARGET_NAME == 2
[aButton setHidden:YES];
[bButton setHidden:NO];
#else
[aButton setHidden:YES];
[bButton setHidden:YES];
#endif

จากโค้ดตัวอย่างเป็นการ implement ง่ายๆนะครับ แค่ทำให้ดูว่า คำสั่ง #if, #elif, #endif รูปแบบเป็นไงบ้าง น่าจะพอเห็นภาพนะครับ

สำหรับ Entry นี้ก็คงจะพอแค่นี้นะครับ Entry หลังๆเกี่ยวกับ Target และ iPad ไว้ได้ลองของจริงแล้วจะเอามาแชร์ให้กันอีกนะครับ ตอนนี้ก็ happy coding สวัสดีครับ ;)

เมษายน 10, 2010 at 4:57 pm ใส่ความเห็น

How to send email from my iPhone app?

ในการพัฒนา iPhone app ถ้าเราต้องการจะส่ง email ด้วย Application ของเรา เราจะสามารถทำได้อย่างไร?

หลายๆคน (เช่นผม) คงคิดว่า “เรียก protocol mail:// เพื่อเปิดโปรแกรม mail.app  ของ iPhone ขึ้นมา” หรือไม่ก็ “generate html ที่เป็น tag mailto ขึ้นมา แล้วใช้่ openUrl ของ appDelegate เรียกเอา” ซึ่งผมเองก็ไม่เคยทดสอบวิธีพวกนี้(แต่คิดว่าน่าจะทำได้) แต่ถึงอย่างนั้นก็มีข้อเสียอย่างรุนแรงทั้งสองวิธี

วิธีเรียก protocol mail:// แอพเราจะถูกปิดตัวลง ส่วนวิธี mailto: ก็ยุ่งยากในการ attach ไฟล์ เช่นการแนบรูปภาพ ต้องแปลง UIImage เป็น NSData ที่ Encode ด้วย Base64 เพื่อที่จะได้ URI Scheme มา attach เป็น body (และผมก็ลองแล้วด้วย springboard crash ไปเลยละครับ)

อันที่จริง มันไม่ได้ยุ่งยากอะไรเลย เพราะ framework มันมีมาให้แล้วหล่ะครับ ชื่อว่า MessageUI.framework ครับ วิธีการ Add ก็ double click ที่ Project Target ของเรา ใน Tab general กด + ข้างล่างใน general link library เลือก MessageUI.framework กด Add แค่นี้ก็เสร็จแล้ว ง่ายซะไม่มี

ลองกดดูที่ Framework จะพบว่า “มี Class ให้ใช้แค่คลาสเดียวเอง คือ MFMailComposeViewController แค่ชื่อคลาสก็บอกแล้วว่าไม่ต้องการอะไรไปมากกว่านี้แล้ว

การใช้งาน ขั้นแรก ให้ import framework ลงไปในคลาสที่เราต้องการใช้งาน framework นี้ แนะนำให้ import ลงในไฟล์ header เลย (.h) เพราะเราจะต้องใช้ protocol ของ framework นี้ด้วย

// myVC.h

#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>

@interface myVC : UIViewController <MFMailComposeViewControllerDelegate> {}

– (IBAction)sendMail:(id)sender;

ในตัวอย่าง Class myVC ของผม ให้มี Action ไว้ปุ่มนึงเพื่อรับ action touch เพื่อส่งเมล์ สังเกตว่าผม Import protocol MFMailComposeViewControllerDelegate ไว้ด้วยนะครับ เอาไว้ทำอะไร เดี๋ยวมาดูกัน ต่อไปเราจะมา Implement method sendMail: กัน

// myVC.m


– (IBAction)sendMail:(id)sender {
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;

[mail setSubject:@”Hello, Developer”];
[self presentModalViewController:mail animated:YES];
}
การ Implement ก็เท่าที่เห็นครับ เนื่องจาก MFMailComposeViewController Subclass มาจาก UIViewController เพราะฉะนั้น เราจึงสามารถใช้คำสั่งแสดงผลแยกออกมาจาก NavigationController อย่างคำสั่ง presentModalViewController:animated: ก็ได้ หรือจะ push ลงใน Navigation Controller ก็ได้อีกเช่นกัน ในส่วนของค่าเริ่มต้น จะใส่หรือไม่ใส่อะไรก็ได้ อย่างในตัวอย่าง ทำการตั้ง Subject เอาไว้ว่า Hello, Developer ซึ่งส่วนอื่นๆก็เพิ่มได้หมด ตั้งแต่ ผู้ส่ง, ผู้รับ , CC, BCC หรือแม้แต่แนบไฟล์ก็ยังทำได้ จะซึ่งการแนบไฟล์ทำได้ดังนี้


[mail setSubject:@”Hello, Developer”];
[mail addAttachmentData:imageData mimeType:@”image/png” fileName:imagePath];
[self presentModalViewController:mail animated:YES];

นี่ครับ เพิ่มบรรทัดต่อบรรทัด imageData นี่เป็นไฟล์ NSData นะครับ ไม่ใช่ UIImage ถ้าไม่รู้ว่าแปลงยังไงก็ใช้คำสั่ง UIImagePNGRepresentation(<#your uiimage#>) หรือ UIImageJPGRepresentation(<#your uiimage#>) ก็ได้ครับ ขึ้นกับว่าต้นฉบับเป็นนามสกุลอะไร แต่ถ้าเป็นไฟล์อื่นก็หาวิธีแปลงเอาเองนะครับ บอกหมดคงไม่ไหว (ฮา) ส่วน mimeType ถ้าไม่รู้ Type ไหนต้องตั้งเป็นอะไร ลองดูที่นี่ครับ http://www.sfsu.edu/training/mimetype.htm มีบอกให้น่าจะเพียงพอ

ต่อไปก็เรื่องที่ค้างกันไว้ Protocol ที่ import ไว้ตั้งแต่ Header จะเห็นตอนเรา allocate ด้วยว่าเรามีการ set delegate มาที่ตัวเอง ซึ่ง method ที่เราใช้เรียกผ่าน delegate ก็คือ mailComposeController:didFinishWithResult:error: แปลง่ายๆก็คือ “ส่งเสร็จแล้วทำอะไร” จาก Parameter จะเห็นว่าจะ return ผลการส่งมาให้ทั้งหมด ส่งเสร็จหรือเปล่า ถ้าไม่เสร็จแล้ว Error ยังไง หน้าที่ของเราก็คือ “กำหนดว่า หลังจากส่งแล้วจะทำอะไรต่อ” ซึ่งผมจะไม่ทำอะไร นอกจาก “ส่งเสร็จแล้วก็ปิดหน้าส่ง email ไปซะ ทำได้ดังนี้

– (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error
{
[controller dismissModalViewControllerAnimated:YES];
}

…เท่านี้ละครับ เสร็จแล้ว ง่ายอย่างไม่น่าเชื่อ สำหรับ Entry นี้ก็จบแค่นี้ละครับ มีอะไรเจ๋งๆง่ายๆ จะมาเขียนแนะนำกันอีก

Happy Coding ครับ

มีนาคม 23, 2010 at 3:26 pm 2 ของความคิดเห็น

Array in Objective-C & How to shuffle members

Class Array container ในภาษา Objective-C คือ NSArray และ NSMutableArray (จริงๆมีอีกอย่างคือ NSArrayController แต่ตอนนี้ยังมีอยู่ใน Cocoa เท่านั้น ไม่มีใน iPhone) ซึ่งความต่างระหว่าง NSArray และ NSMutableArray ก็คือ “ความสามารถในการแก้ไขภายหลังการ Initialize แล้ว” พูดง่ายๆ NSArray มี access attribute เป็น read-only แต่ NSMutableArray เป็น read-write นั่นเอง

คำถามต่อมาคือ “แล้วใช้ตัวไหนดี?” คำตอบก็คือ “ใช้ได้ทั้งคู่ครับ แตกต่างกันที่ Performance เล็กน้อยเท่านั้น” โดยส่วนตัวผมใช้ตามความสะดวก ถ้าจำเป็นต้อง read-write ก็ใช้ NSMutableArray ซึ่งการใช้งาน NSMutableArray ก็ดูตาม Document ได้เลย

อย่างที่บอกว่า NSMutableArray สามารถแก้ไขหลังจาก Initialize ได้ ดังนั้นแน่นอนว่า “ต้อง sort ได้ด้วย” ซึ่งใน Entry นี้ผมจะนำเสนอการ sort แบบ Random ผมต้องการ sort members ใน mutable array แบบสุ่ม ผมสามารถทำได้ดังนี้

int randomSort(id obj1, id obj2, void *context ) {
    // returns random number -1 0 1
    return (arc4random()%3 - 1);
}

- (void)shuffle {
    // call custom sort function
    NSMutableArray *puzzles = [NSMutableArray arrayWithObject:@"1", @"2", @"3", @"4", @"5", nil];
    [puzzles sortUsingFunction:randomSort context:nil];

    NSLog(@"Members after shuffle = %@", puzzles); 
}

จากโค้ด ผมสร้าง mutable array ขึ้นมา 1 ชุดแล้วสั่งให้ sort ด้วยฟังก์ชั่น randomSort ซึ่งใน randomSort จะทำการสุ่มค่า 3 ค่า คือ -1, 0, 1 ซึ่ง -1 หมายถึง การเรียงแบบตามลำดับ(NSOrderAscending) 0 หมายถึง การเรียงแบบปกติ (NSOrderSame) และ 1  หมายถึงการเรียงแบบกลับด้าน(NSOrderDescending) ซึ่งฟังก์ชั่น sort จะจัดลำดับของ member แต่ละตัวจากผลที่ได้จากสุ่มนั่นเอง

ส่วน arc4random เป็นฟังก์ชั่นสุ่มของ ภาษา C ครับ การใช้คำสั่ง rand() หรือ random() มันเป็นการสุ่มที่ไม่ dynamic เท่าไหร่นัก ผลลัพธ์ที่ได้จากการสุ่มจะเหมือนกันทุกครั้ง

เพียงเท่านี้เราก็สามารถสุ่มสมาชิกใน mutable array ได้แล้ว นอกจากนี้ยังมีการ sort อื่นๆได้อีกนะครับ เจออันไหนน่าสนใจผมจะมาแนะนำอีกใน Entry ต่อๆไปนะครับ

#reference http://stackoverflow.com/questions/56648/whats-the-best-way-to-shuffle-an-nsmutablearray

กุมภาพันธ์ 4, 2010 at 12:45 am ใส่ความเห็น

Older Posts


del.icio.us For iPhone dev

Post Calendar

กันยายน 2019
พฤ อา
« ธ.ค.    
 1
2345678
9101112131415
16171819202122
23242526272829
30