[iOS Dev] Background Transfer with NSURLSession

เรื่องของการรับส่งข้อมูลในขณะที่ App ทำงานอยู่เบื้องหลัง หรือ Background Transfer เป็นสิ่งที่ Apple ทำให้มีตั้งแต่ iOS 6 แล้ว เพียงแต่ตอน iOS 6 จะใช้ Model ของการ "จำกัดเวลา" หลังจากที่ App ถูกปิดและทำงานใน Background ซึ่งปัญหาใหญ่ของการทำแบบนั้นคือ "เราไม่สามารถทำงานกับข้อมูลขนาดใหญ่ได้" 

และใน iOS 7 ด้วย Model ของการทำ Multitasking แบบใหม่ ทำให้เราสามารถที่จะทำ Background Transfer ได้อย่างสมบูรณ์แบบ โดยจะมีลักษณะคร่าวๆ ดังนี้
  • iOS จะทำการจัดการการ Upload และ Download
  • การส่งข้อมูลจะถูกทำต่อไปแม้ User จะปิด Application ไปแล้ว
  • เวลาในการทำ Background Transfer ไม่จำกัด
  • การ Transfer สามารถสลับการทำงานระหว่าง Foreground และ Background ได้ตลอดเวลา
... และแน่นอน วันนี้เราจะมาทำ App ง่ายๆ กัน
(ใครสนใจศึกษาแนะนำ Session 204: What's New with Multitasking ของ WWDC ปี 2013

App นี้มีแค่ 2 ปุ่มอยู่บน Navigation Bar โดยจะมี 2 เหตุการณ์ที่ผมจำลองขึ้นมา
  • กดปุ่ม Fetch จากนั้นกดปุ่ม Home เพื่อให้ App เข้าสู่ Background Mode จากนั้นกดปุ่ม Home 2 ครั้งเพื่อให้เข้า Multitasking พอเลื่อนมาที่ App เรา เราก็จะยังเห็น Progress Bar วิ่งอยู่ และแสดงผลรูปภาพหลังจากที่โหลดเสร็จ
  • กดปุ่ม Fetch พอเวลาผ่านไปสักระยะ (เอาสัก 50%) แล้วกดปุ่ม Crash (ผมเขียนให้ทำอะไรสักอย่างเพื่อให้ App มัน Crash) จากนั้นเมื่อเปิด App ขึ้นมาอีกครั้ง ถ้ารูปภาพถูกโหลดเสร็จ ก็จะทำการแสดงรูปภาพ 

พระเอกของเราในวันนี้คือ NSURLSession นั่นเอง (เป็น Library ที่ Apple บอกว่าทำมาเพื่อแทนที่ NSURLConnection) โดย ProgressView ที่ผมใช้คือ MRProgress เนื่องจากอยากได้แบบ Circular สวยๆ เท่านั้นเอง (ผมใช้ Cocoapods นะ :)

เริ่มต้นจากการประกาศของที่ต้องใช้ในการทำงานครั้งนี้ก่อน (ดูเอาเองนะ)
เนื่องจากการทำ Background Transfer นั้นไม่อนุญาติให้เขียนในรูปแบบของ Blocks ได้ 
เราจึงต้องทำผ่าน Delegate เท่านั้น (AFNetworking น่าจะเขียนไว้ให้ทำได้นะ ยังไม่ได้ลอง)


ในนี้ไม่มีอะไรนอกจาก ซ่อน ProgressBar ไว้ก่อนในตอนแรก แล้วก็กำหนดค่าเริ่มต้นให้ NSURLSession Object ให้ทำงานแบบ Background ด้วย Configuration


Action ของทั้ง 2 ปุ่ม ปุ่มแรกคือปุ่ม Fetch ซึ่งจะทำการสร้าง Download Task จาก NSURLRequest และโดยธรรมชาติของ NSURLSessionTask นั้นสถานะเริ่มต้นจะเป็นการ Pause หลังจากถูกสร้าง ดังนั้นก็เราจึงต้องทำการ Resume เพื่อให้ Task ดังกล่าวเริ่มทำงาน


มาดู Delegate method กันบ้าง มีทั้งหมด 3 method สำหรับ NSURLSessionDownloadDelegate Protocol และ 2 method สำหรับ NSURLSessionDelegate Protocol ที่เราจำเป็นต้อง Implement โดยในตัวอย่างครั้งนี้จะไม่มีการ Resume ดังนั้นก็จะมี 1 method ที่ไม่ได้เขียนอะไรเอาไว้

โดย method แรกจะ handle เมื่อทำการโหลดข้อมูลเสร็จและบันทึกลง Temporary Storage ที่ต้องทำก็เพียงเก็บข้อมูลที่โหลดเสร็จเก็บลงใน Document Directory แล้วทำการแสดงผลรูปภาพเท่านั้นเอง (การทำ Cache) ส่วน method ที่สองจะทำการอัพเดท progress bar ระหว่างการโหลดข้อมูล


ส่วน delegate method ของ NSURLSession Protocol เราจะใช้ handle ในกรณีที่ Session นั้นทำการโหลดข้อมูลเสร็จแล้ว และ method ที่ handle ในกรณีที่ Background Transfer Process เสร็จหมดแล้ว โดยใน method นี้จะเป็นการบอก Application Delegate เพื่อให้ iOS จัดการตรงนี้ให้


ใน Application Delegate เราจึงต้องไป Implement ให้ทำงานตอนที่ App ส่งข้อความดังกล่าวไปบอกด้วย โดยให้สร้าง CompletionBlock ไว้ที่ Header File และเขียน Application Delegate method เพิ่มเติมด้วย โดยผมใส่ Local Notification เพื่อความน่ารัก จะได้รู้ว่าเมื่อไหร่ที่โหลดข้อมูลเสร็จ



จบแล้ว ยังไงลองจำลองเหตุการณ์ที่ผมได้บอกไว้ด้านบนนะครับ ว่าใช้งานได้จริงไหม ... โดยการทำ Background Transfer นี้ยังเอาใช้งานได้อีกหลายสถานการณ์เลย เช่นการ Upload/Download ข้อมูลที่มีขนาดใหญ่ และต่อยอดไปสู่ Feature ใหม่ๆ อย่าง Background Fetch และ Remote Notification ไว้มีโอกาสจะเขียนให้อ่านกันนะ (แท้จริงแล้วยังไม่เคยทำเลย ฮ่าฮ่า)

Popular posts from this blog

12 วิธี การบริการและดูแลลูกค้าในร้าน Starbucks

"อีสุกอีใส" ประสบการณ์เมื่อต้องมาเป็นตอนอายุ 22

[Android Dev] การติดตั้ง Eclipse+AndroidSDK เพื่อพัฒนาโปรแกรมบน Android