เคล็ดลับประสิทธิภาพของ iOS เพื่อให้แอปของคุณมีประสิทธิภาพมากขึ้น

เผยแพร่แล้ว: 2022-03-10
สรุปโดยย่อ ↬ ประสิทธิภาพที่ดีเป็นสิ่งสำคัญในการมอบประสบการณ์ที่ดีแก่ผู้ใช้ และผู้ใช้ iOS มักมีความคาดหวังสูงเกี่ยวกับแอปของตน แอปที่ช้าและไม่ตอบสนองอาจทำให้ผู้ใช้เลิกใช้แอปของคุณ หรือแย่กว่านั้นคือให้คะแนนที่ไม่ดี

แม้ว่าฮาร์ดแวร์ iOS สมัยใหม่จะมีประสิทธิภาพเพียงพอที่จะจัดการกับงานที่ซับซ้อนและซับซ้อนได้หลายอย่าง แต่อุปกรณ์อาจยังคงรู้สึกไม่ตอบสนองหากคุณไม่ระมัดระวังเกี่ยวกับประสิทธิภาพของแอป ในบทความนี้ เราจะพิจารณาเคล็ดลับการเพิ่มประสิทธิภาพห้าประการที่จะทำให้แอปของคุณตอบสนองได้ดีขึ้น

1. Dequeue เซลล์ที่ใช้ซ้ำได้

คุณอาจเคยใช้ tableView.dequeueReusableCell(withIdentifier:for:) ภายใน tableView(_:cellForRowAt:) มาก่อน เคยสงสัยไหมว่าทำไมคุณต้องทำตาม API ที่น่าอึดอัดใจนี้ แทนที่จะส่งผ่านอาร์เรย์ของเซลล์เข้าไป? มาดูเหตุผลของเรื่องนี้กัน

สมมติว่าคุณมีมุมมองตารางที่มีหนึ่งพันแถว หากไม่ใช้เซลล์ที่นำกลับมาใช้ใหม่ได้ เราจะต้องสร้างเซลล์ใหม่สำหรับแต่ละแถวดังนี้

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // Create a new cell whenever cellForRowAt is called. let cell = UITableViewCell() cell.textLabel?.text = "Cell \(indexPath.row)" return cell }

อย่างที่คุณอาจคิดไว้ วิธีนี้จะเพิ่มเซลล์นับพันเซลล์ลงในหน่วยความจำของอุปกรณ์เมื่อคุณเลื่อนลงมาด้านล่าง ลองนึกภาพว่าจะเกิดอะไรขึ้นหากแต่ละเซลล์มี UIImageView และข้อความจำนวนมาก: การโหลดทั้งหมดพร้อมกันอาจทำให้แอปมีหน่วยความจำไม่เพียงพอ! นอกจากนั้น ทุกเซลล์จะต้องมีการจัดสรรหน่วยความจำใหม่ในระหว่างการเลื่อน หากคุณเลื่อนมุมมองตารางอย่างรวดเร็ว หน่วยความจำขนาดเล็กจำนวนมากจะถูกจัดสรรทันที และกระบวนการนี้จะทำให้ UI แย่!

ในการแก้ไขปัญหานี้ Apple ได้จัดเตรียม dequeueReusableCell(withIdentifier:for:) ให้กับเรา การใช้เซลล์ซ้ำทำงานโดยการวางเซลล์ที่ไม่ปรากฏบนหน้าจออีกต่อไปในคิว และเมื่อเซลล์ใหม่กำลังจะปรากฏบนหน้าจอ (เช่น เซลล์ที่ตามมาด้านล่างเมื่อผู้ใช้เลื่อนลง) มุมมองตารางจะ ดึงเซลล์จากคิวนี้และแก้ไขใน cellForRowAt indexPath: เมธอด

กลไกคิวการนำเซลล์กลับมาใช้ใหม่
คิวการนำเซลล์มาใช้ซ้ำทำงานอย่างไรใน iOS (ตัวอย่างขนาดใหญ่)

ด้วยการใช้คิวในการจัดเก็บเซลล์ มุมมองตารางจึงไม่จำเป็นต้องสร้างเซลล์เป็นพันเซลล์ แต่ต้องการเซลล์เพียงพอที่จะครอบคลุมพื้นที่ของมุมมองตารางแทน

ด้วยการใช้ dequeueReusableCell เราสามารถลดหน่วยความจำที่แอพใช้และทำให้หน่วยความจำหมดน้อยลง!

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

2. การใช้หน้าจอเปิดที่ดูเหมือนหน้าจอเริ่มต้น

ตามที่กล่าวไว้ใน Human Interface Guidelines (HIG) ของ Apple หน้าจอเปิดสามารถใช้เพื่อปรับปรุงการรับรู้ของการตอบสนองของแอพ:

“มีจุดประสงค์เพื่อเพิ่มการรับรู้ของแอปของคุณให้เปิดใช้งานได้อย่างรวดเร็วและพร้อมใช้งานทันที ทุกแอปต้องมีหน้าจอเริ่มต้น”

เป็นเรื่องปกติที่จะใช้หน้าจอเริ่มต้นเป็นหน้าจอเริ่มต้นเพื่อแสดงการสร้างแบรนด์หรือเพื่อเพิ่มแอนิเมชั่นการโหลด ออกแบบหน้าจอเริ่มต้นให้เหมือนกับหน้าจอแรกของแอพของคุณ ตามที่ Apple กล่าวไว้:

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

“หน้าจอเปิดตัวไม่ใช่โอกาสในการสร้างแบรนด์ อย่าออกแบบประสบการณ์การเข้าใช้งานที่ดูเหมือนหน้าจอเริ่มต้นหรือหน้าต่าง "เกี่ยวกับ" อย่าใส่โลโก้หรือองค์ประกอบการสร้างแบรนด์อื่นๆ เว้นแต่ว่าเป็นส่วนคงที่ในหน้าจอแรกของแอปของคุณ”

การใช้หน้าจอเริ่มต้นเพื่อจุดประสงค์ในการโหลดหรือสร้างแบรนด์อาจทำให้เวลาใช้งานครั้งแรกช้าลงและทำให้ผู้ใช้รู้สึกว่าแอปทำงานช้า

เมื่อคุณเริ่มโปรเจ็กต์ iOS ใหม่ LaunchScreen.storyboard เปล่าจะถูกสร้างขึ้น หน้าจอนี้จะแสดงให้ผู้ใช้เห็นในขณะที่แอปโหลดตัวควบคุมมุมมองและเลย์เอาต์

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

ตัวอย่างเช่น หน้าจอเริ่มต้นของแอป Safari จะคล้ายกับมุมมองแรก :

เปิดหน้าจอและมุมมองแรกจะคล้ายกัน
การเปรียบเทียบหน้าจอเปิดและการดูครั้งแรกของแอพ Safari (ตัวอย่างขนาดใหญ่)

สตอรี่บอร์ดของหน้าจอเปิดใช้นั้นเหมือนกับไฟล์สตอรีบอร์ดอื่นๆ ยกเว้นว่าคุณสามารถใช้คลาส UIKit มาตรฐานเท่านั้น เช่น UIViewController, UITabBarController และ UINavigationController หากคุณพยายามใช้คลาสย่อยที่กำหนดเองอื่นๆ (เช่น UserViewController) Xcode จะแจ้งให้คุณทราบว่าห้ามใช้ชื่อคลาสที่กำหนดเอง

Xcode แสดงข้อผิดพลาดเมื่อใช้คลาสที่กำหนดเอง
กระดานเรื่องราวหน้าจอเปิดใช้ต้องไม่มีคลาสมาตรฐานที่ไม่ใช่ UIKit (ตัวอย่างขนาดใหญ่)

สิ่งที่ควรทราบอีกประการหนึ่งคือ UIActivityIndicatorView จะไม่เคลื่อนไหวเมื่อวางบนหน้าจอเริ่มต้น เนื่องจาก iOS จะสร้างภาพนิ่งจากกระดานเรื่องราวหน้าจอเปิดตัวและแสดงให้ผู้ใช้เห็น (มีการกล่าวถึงสั้น ๆ ในการนำเสนอ WWDC 2014 “ Platforms State of the Union” ประมาณ 01:21:56 น.)

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

การอ่านที่แนะนำ : แอพมือถือพร้อมคุณสมบัติจดจำใบหน้า: วิธีทำให้เป็นจริง

3. การฟื้นฟูสถานะสำหรับผู้ควบคุมการดู

การเก็บรักษาและการกู้คืนสถานะทำให้ผู้ใช้สามารถกลับสู่สถานะ UI เดิมได้ตั้งแต่ก่อนออกจากแอป บางครั้ง เนื่องจากหน่วยความจำไม่เพียงพอ ระบบปฏิบัติการอาจจำเป็นต้องลบแอพของคุณออกจากหน่วยความจำในขณะที่แอพอยู่ในพื้นหลัง และแอพอาจสูญเสียการติดตามสถานะ UI ล่าสุด หากไม่ได้รับการรักษาไว้ อาจทำให้ผู้ใช้สูญเสียงาน กำลังดำเนินการ!

ในหน้าจอมัลติทาสก์ เราจะเห็นรายการแอพที่วางไว้เบื้องหลัง เราอาจสันนิษฐานว่าแอปเหล่านี้ยังคงทำงานในพื้นหลัง ในความเป็นจริง แอพเหล่านี้บางตัวอาจถูกระบบฆ่าและรีสตาร์ทเนื่องจากความต้องการหน่วยความจำ สแนปชอตของแอปที่เราเห็นในมุมมองมัลติทาสก์เป็นภาพหน้าจอที่ระบบถ่ายโดยทันทีเมื่อเราออกจากแอป (เช่น ไปที่หน้าจอหลักหรือหน้าจอมัลติทาสก์)

iOS สร้างภาพลวงตาของแอปที่ทำงานอยู่เบื้องหลังด้วยการจับภาพหน้าจอของมุมมองล่าสุด
ภาพหน้าจอของแอปที่ iOS ถ่ายเมื่อผู้ใช้ออกจากแอป (ตัวอย่างขนาดใหญ่)

iOS ใช้ภาพหน้าจอเหล่านี้เพื่อสร้างภาพลวงตาว่าแอปยังคงทำงานอยู่หรือยังคงแสดงมุมมองนี้อยู่ ในขณะที่แอปอาจถูกยกเลิกหรือรีสตาร์ทในพื้นหลังแล้วในขณะที่ยังแสดงภาพหน้าจอเดิม

คุณเคยมีประสบการณ์ในการเรียกใช้แอปจากหน้าจอมัลติทาสก์ว่าแอปแสดงอินเทอร์เฟซผู้ใช้ที่แตกต่างจากสแน็ปช็อตที่แสดงในมุมมองมัลติทาสก์หรือไม่ เนื่องจากแอปไม่ได้ใช้กลไกการกู้คืนสถานะ และข้อมูลที่แสดงหายไปเมื่อแอปถูกฆ่าในเบื้องหลัง การดำเนินการนี้อาจนำไปสู่ประสบการณ์ที่ไม่ดี เนื่องจากผู้ใช้คาดว่าแอปของคุณจะอยู่ในสถานะเดียวกับเมื่อออกจากแอป

จากบทความของ Apple:

“พวกเขาคาดหวังว่าแอปของคุณจะอยู่ในสถานะเดียวกับตอนที่ออกจากแอป การเก็บรักษาและการกู้คืนสถานะทำให้มั่นใจได้ว่าแอปของคุณจะกลับสู่สถานะก่อนหน้าเมื่อเปิดใช้งานอีกครั้ง”

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

ในการเปิดใช้งานการบันทึกและกู้คืนสถานะ เราสามารถใช้สองวิธีนี้ใน AppDelegate.swift :

 func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool { return true }
 func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool { return true }

การดำเนินการนี้จะบอกให้แอปบันทึกและกู้คืนสถานะของแอปพลิเคชันโดยอัตโนมัติ

ต่อไป เราจะบอกแอปว่าต้องรักษามุมมองตัวควบคุมใดไว้ เราทำได้โดยระบุ "รหัสการกู้คืน" ในกระดานเรื่องราว :

การตั้งค่า ID การกู้คืนในกระดานเรื่องราว
การตั้งค่า ID การกู้คืนในกระดานเรื่องราว (ตัวอย่างขนาดใหญ่)

คุณยังสามารถเลือก “ใช้ Storyboard ID” เพื่อใช้ ID กระดานเรื่องราวเป็น ID การกู้คืนได้อีกด้วย

ในการตั้งค่ารหัสการคืนค่าในโค้ด เราสามารถใช้คุณสมบัติ restorationIdentifier ของตัวควบคุมการดู

 // ViewController.swift self.restorationIdentifier = "MainVC"

ระหว่างการรักษาสถานะ ตัวควบคุมมุมมองหรือมุมมองใดๆ ที่ได้รับมอบหมายตัวระบุการกู้คืนจะมีสถานะบันทึกลงในดิสก์

ตัวระบุการฟื้นฟูสามารถจัดกลุ่มเข้าด้วยกันเพื่อสร้างเส้นทางการฟื้นฟู ตัวระบุถูกจัดกลุ่มโดยใช้ลำดับชั้นของมุมมอง จากตัวควบคุมรูทไปยังตัวควบคุมมุมมองแอ็คทีฟปัจจุบัน สมมติว่า MyViewController ฝังอยู่ในตัวควบคุมการนำทาง ซึ่งฝังอยู่ในตัวควบคุมแถบแท็บอื่น สมมติว่าพวกเขากำลังใช้ชื่อคลาสของตัวเองเป็นตัวระบุการคืนค่า เส้นทางการกู้คืนจะมีลักษณะดังนี้:

 TabBarController/NavigationController/MyViewController

เมื่อผู้ใช้ออกจากแอปโดยให้ MyViewController เป็นตัวควบคุมมุมมองแอ็คทีฟ เส้นทางนี้จะถูกบันทึกโดยแอป จากนั้นแอปจะจำลำดับชั้นการดูก่อนหน้าที่แสดง ( ตัวควบคุมแถบแท็บ → ตัว ควบคุมการนำทาง → ตัวควบคุม มุมมองของฉัน )

หลังจากกำหนดตัวระบุการคืนค่าแล้ว เราจะต้องใช้เมธอด encodeRestorableState(พร้อม coder:) และ decodeRestorableState(พร้อม coder:) สำหรับแต่ละตัวควบคุมมุมมองที่สงวนไว้ สองวิธีนี้ช่วยให้เราระบุข้อมูลที่ต้องบันทึกหรือโหลด และวิธีการเข้ารหัสหรือถอดรหัส

มาดูตัวควบคุมการดู:

 // MyViewController.swift​ // MARK: State restoration // UIViewController already conforms to UIStateRestoring protocol by default extension MyViewController { // will be called during state preservation override func encodeRestorableState(with coder: NSCoder) { // encode the data you want to save during state preservation coder.encode(self.username, forKey: "username") super.encodeRestorableState(with: coder) } // will be called during state restoration override func decodeRestorableState(with coder: NSCoder) { // decode the data saved and load it during state restoration if let restoredUsername = coder.decodeObject(forKey: "username") as? String { self.username = restoredUsername } super.decodeRestorableState(with: coder) } }

อย่าลืมเรียกใช้ superclass ที่ด้านล่างวิธีการของคุณเอง เพื่อให้แน่ใจว่าคลาสพาเรนต์มีโอกาสที่จะบันทึกและกู้คืนสถานะ

เมื่อวัตถุถอดรหัสเสร็จแล้ว applicationFinishedRestoringState() จะถูกเรียกเพื่อบอกตัวควบคุมการดูว่าสถานะได้รับการคืนค่าแล้ว เราสามารถอัปเดต UI สำหรับตัวควบคุมการดูในวิธีนี้

 // MyViewController.swift​ // MARK: State restoration // UIViewController already conforms to UIStateRestoring protocol by default extension MyViewController { ... override func applicationFinishedRestoringState() { // update the UI here self.usernameLabel.text = self.username } }

ที่นั่นคุณมีมัน! นี่เป็นวิธีการที่จำเป็นในการดำเนินการรักษาและกู้คืนสถานะสำหรับแอปของคุณ โปรดทราบว่าระบบปฏิบัติการจะลบสถานะที่บันทึกไว้เมื่อแอปถูกบังคับปิดโดยผู้ใช้ เพื่อหลีกเลี่ยงไม่ให้ติดค้างอยู่ในสถานะที่ใช้งานไม่ได้ในกรณีที่มีสิ่งผิดปกติเกิดขึ้นกับการรักษาและกู้คืนสถานะ

นอกจากนี้ อย่าจัดเก็บข้อมูลแบบจำลองใดๆ (เช่น ข้อมูลที่ควรจะบันทึกไว้ใน UserDefaults หรือ Core Data) ไว้ในสถานะ แม้ว่าอาจดูเหมือนสะดวกที่จะทำเช่นนั้นก็ตาม ข้อมูลสถานะจะถูกลบออกเมื่อผู้ใช้บังคับออกจากแอปของคุณ และคุณจะไม่ต้องการสูญเสียข้อมูลโมเดลด้วยวิธีนี้อย่างแน่นอน

ในการทดสอบว่าการรักษาและฟื้นฟูสภาพทำงานได้ดีหรือไม่ ให้ทำตามขั้นตอนด้านล่าง:

  1. สร้างและเปิดใช้แอปโดยใช้ Xcode
  2. ไปที่หน้าจอด้วยการเก็บรักษาและการกู้คืนสถานะที่คุณต้องการทดสอบ
  3. กลับไปที่หน้าจอหลัก (โดยการปัดขึ้นหรือดับเบิลคลิกปุ่มโฮม หรือกด Shift ⇧ + Cmd ⌘ + H ในโปรแกรมจำลอง) เพื่อส่งแอปไปที่พื้นหลัง
  4. หยุดแอปใน Xcode โดยกดปุ่ม
  5. เปิดแอปอีกครั้งและตรวจสอบว่าสถานะได้รับการกู้คืนสำเร็จหรือไม่

เนื่องจากส่วนนี้ครอบคลุมเฉพาะพื้นฐานของการรักษาและฟื้นฟูสภาพเท่านั้น ฉันจึงแนะนำบทความต่อไปนี้โดย Apple Inc. สำหรับความรู้เชิงลึกเพิ่มเติมเกี่ยวกับการฟื้นฟูสถานะ:

  1. การรักษาและฟื้นฟูสภาพ
  2. กระบวนการถนอม UI
  3. กระบวนการฟื้นฟู UI

4. ลดการใช้มุมมองที่ไม่ทึบแสงให้มากที่สุด

มุมมองทึบแสงเป็นมุมมองที่ไม่มีความโปร่งใส หมายความว่าองค์ประกอบ UI ใดๆ ที่วางอยู่ด้านหลังจะไม่ปรากฏให้เห็นเลย เราสามารถตั้งค่าให้มุมมองทึบแสงในตัวสร้างอินเทอร์เฟซ:

ซึ่งจะแจ้งระบบการวาดให้ข้ามการวาดสิ่งที่อยู่เบื้องหลังมุมมองนี้
ตั้งค่า UIView เป็นทึบในกระดานเรื่องราว (ตัวอย่างขนาดใหญ่)

หรือเราสามารถทำได้โดยทางโปรแกรมด้วยคุณสมบัติ isOpaque ของ UIView:

 view.isOpaque = true

การตั้งค่ามุมมองเป็นแบบทึบจะทำให้ระบบการวาดปรับประสิทธิภาพการวาดบางส่วนในขณะที่แสดงผลหน้าจอ

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

คุณสามารถตรวจสอบว่าเลเยอร์ใดกำลังผสม (ไม่ทึบแสง) ใน iOS Simulator ได้โดยตรวจสอบ DebugColor Blended Layers

สีเขียวเป็นสีผสมไม่มีสี สีแดงเป็นชั้นผสม
แสดงเลเยอร์ผสมสีใน Simulator

หลังจากตรวจสอบตัวเลือก Color Blended Layers แล้ว คุณจะเห็นว่าบางมุมมองเป็นสีแดงและบางส่วนเป็นสีเขียว สีแดงแสดงว่ามุมมองไม่ทึบแสง และการแสดงผลเป็นผลลัพธ์จากเลเยอร์ที่ซ้อนอยู่ด้านหลัง สีเขียวแสดงว่าภาพไม่ชัดและไม่มีการผสม

ด้วยพื้นหลังสีทึบ เลเยอร์ไม่จำเป็นต้องผสมกับเลเยอร์อื่น
กำหนดสีพื้นหลังที่ไม่โปร่งใสให้กับ UILabel เมื่อใดก็ตามที่เป็นไปได้เพื่อลดเลเยอร์ที่ผสมสี (ตัวอย่างขนาดใหญ่)

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

วิธีหนึ่งที่คุณสามารถเพิ่มประสิทธิภาพแอปได้คือการลดจำนวนการดูที่ถูกเน้นด้วยสีแดงให้มากที่สุด

ด้วยการเปลี่ยน label.backgroundColor = UIColor.clear เป็น label.backgroundColor = UIColor.white เราสามารถลดการผสมเลเยอร์ระหว่างป้ายกำกับและเลเยอร์การดูด้านหลังได้

การใช้สีพื้นหลังโปร่งใสจะทำให้เลเยอร์ผสมกัน
ป้ายกำกับจำนวนมากถูกเน้นด้วยสีแดงเนื่องจากสีพื้นหลังโปร่งใส ทำให้ iOS คำนวณสีพื้นหลังด้วยการผสมผสานมุมมองด้านหลัง (ตัวอย่างขนาดใหญ่)

คุณอาจสังเกตเห็นว่า แม้ว่าคุณจะตั้งค่า UIImageView เป็นแบบทึบแสงและกำหนดสีพื้นหลังให้กับมัน ตัวจำลองจะยังคงแสดงสีแดงในมุมมองภาพ อาจเป็นเพราะภาพที่คุณใช้สำหรับการดูภาพมีช่องอัลฟา

หากต้องการลบช่องอัลฟาของรูปภาพ คุณสามารถใช้แอปดูตัวอย่างเพื่อสร้างภาพซ้ำ ( Shift ⇧ + Cmd ⌘ + S ) และยกเลิกการเลือกช่องทำเครื่องหมาย "Alpha" เมื่อบันทึก

ยกเลิกการเลือกช่องทำเครื่องหมาย "อัลฟ่า" เมื่อบันทึกภาพเพื่อทิ้งช่องอัลฟา
ยกเลิกการเลือกช่องทำเครื่องหมาย 'อัลฟ่า' เมื่อบันทึกภาพเพื่อทิ้งช่องอัลฟา (ตัวอย่างขนาดใหญ่)

5. ส่งฟังก์ชันการประมวลผลจำนวนมากไปยังเธรดพื้นหลัง (GCD)

เนื่องจาก UIKit ใช้งานได้กับเธรดหลักเท่านั้น การประมวลผลจำนวนมากบนเธรดหลักจะทำให้ UI ช้าลง UIKit ใช้เธรดหลักไม่เพียงเพื่อจัดการและตอบสนองต่ออินพุตของผู้ใช้เท่านั้น แต่ยังเพื่อวาดหน้าจอ

กุญแจสำคัญในการทำให้แอปตอบสนองคือการย้ายงานการประมวลผลจำนวนมากไปยังเธรดพื้นหลังให้ได้มากที่สุด หลีกเลี่ยงการทำการคำนวณที่ซับซ้อน การสร้างเครือข่าย และการดำเนินการ IO จำนวนมาก (เช่น การอ่านและการเขียนลงดิสก์) บนเธรดหลัก

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

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

หลีกเลี่ยงการรันงานที่เน้นประสิทธิภาพหรือใช้เวลานานบนเธรดหลัก
นี่คือวิธีที่เธรดหลักจัดการกับงาน UI และเหตุใดจึงทำให้ UI หยุดทำงานเมื่อทำงานหนัก (ตัวอย่างขนาดใหญ่)

โดยค่าเริ่มต้น โค้ดภายในวิธีวงจรชีวิตของตัวควบคุมมุมมอง (เช่น viewDidLoad) และฟังก์ชัน IBOutlet จะถูกดำเนินการบนเธรดหลัก ในการย้ายงานการประมวลผลจำนวนมากไปยังเธรดพื้นหลัง เราสามารถใช้คิว Grand Central Dispatch ที่ Apple จัดหาให้

นี่คือเทมเพลตสำหรับการสลับคิว:

 // Switch to background thread to perform heavy task. DispatchQueue.global(qos: .default).async { // Perform heavy task here. // Switch back to main thread to perform UI-related task. DispatchQueue.main.async { // Update UI. } }

qos หมายถึง "คุณภาพของการบริการ" ค่าคุณภาพการบริการที่แตกต่างกันบ่งบอกถึงลำดับความสำคัญที่แตกต่างกันสำหรับงานที่ระบุ ระบบปฏิบัติการจะจัดสรรเวลา CPU และปริมาณการประมวลผล I/O ของพลังงาน CPU สำหรับงานที่จัดสรรในคิวที่มีค่า QoS สูงกว่า ซึ่งหมายความว่างานจะเสร็จเร็วขึ้นในคิวที่มีค่า QoS สูงกว่า ค่า QoS ที่สูงขึ้นจะใช้พลังงานมากขึ้นเนื่องจากใช้ทรัพยากรมากขึ้น

นี่คือรายการค่า QoS จากลำดับความสำคัญสูงสุดไปต่ำสุด:

ค่าคุณภาพการบริการของคิวเรียงตามประสิทธิภาพและประสิทธิภาพพลังงาน
ค่าคุณภาพการบริการของคิวเรียงตามประสิทธิภาพและประสิทธิภาพการใช้พลังงาน (แสดงตัวอย่างขนาดใหญ่)

Apple ได้จัดเตรียมตารางที่มีประโยชน์พร้อมตัวอย่างค่า QoS ที่จะใช้สำหรับงานต่างๆ

สิ่งหนึ่งที่ต้องจำไว้คือควรรันโค้ด UIKit ทั้งหมดบนเธรดหลักเสมอ การแก้ไขอ็อบเจ็กต์ UIKit (เช่น UILabel และ UIImageView ) บนเธรดพื้นหลังอาจมีผลที่ไม่ได้ตั้งใจ เช่น UI ที่ไม่ได้อัปเดตจริงๆ เกิดการขัดข้อง และอื่นๆ

จากบทความของ Apple:

“การอัปเดต UI บนเธรดอื่นที่ไม่ใช่เธรดหลักเป็นข้อผิดพลาดทั่วไปที่อาจส่งผลให้พลาดการอัปเดต UI, ข้อบกพร่องด้านภาพ, ข้อมูลเสียหาย และการขัดข้อง”

ฉันแนะนำให้ดูวิดีโอ WWDC 2012 ของ Apple เกี่ยวกับการทำงานพร้อมกันของ UI เพื่อให้เข้าใจวิธีสร้างแอปที่ตอบสนองได้ดียิ่งขึ้น

หมายเหตุ

ข้อเสียของการเพิ่มประสิทธิภาพคือคุณต้องเขียนโค้ดเพิ่มเติมหรือกำหนดการตั้งค่าเพิ่มเติมนอกเหนือจากฟังก์ชันการทำงานของแอป การทำเช่นนี้อาจทำให้แอปของคุณส่งช้ากว่าที่คาดไว้ และคุณจะมีโค้ดเพิ่มเติมที่จะรักษาในอนาคต และโค้ดที่มากขึ้นหมายถึงข้อบกพร่องที่มากขึ้น

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

แหล่งข้อมูลเพิ่มเติม

  • “A Suite of Delicious iOS Eye Candy,” Tim Oliver, งาน Tokyo iOS Meetup 2018 (วิดีโอ)
  • “การสร้างอินเทอร์เฟซผู้ใช้พร้อมกันบน iOS” Andy Matuschak, WWDC 2012 (วิดีโอ)
  • “การรักษา UI ของแอพของคุณตลอดการเปิดตัว” Apple
  • “คู่มือการเขียนโปรแกรมการทำงานพร้อมกัน: คิวการส่ง” เอกสารจัดเก็บเอกสาร Apple
  • “ตัวตรวจสอบเธรดหลัก” Apple