ฉันมีวิธีการที่ยอมรับบล็อกและบล็อกเสร็จสิ้น บล็อกแรกควรทำงานในพื้นหลังในขณะที่บล็อกการเสร็จสมบูรณ์ควรทำงานในคิวใดก็ตามที่เมธอดเรียก
ในช่วงหลังฉันใช้มาตลอดdispatch_get_current_queue()
แต่ดูเหมือนว่าจะเลิกใช้งานใน iOS 6 ขึ้นไป ฉันควรใช้อะไรแทน?
ฉันมีวิธีการที่ยอมรับบล็อกและบล็อกเสร็จสิ้น บล็อกแรกควรทำงานในพื้นหลังในขณะที่บล็อกการเสร็จสมบูรณ์ควรทำงานในคิวใดก็ตามที่เมธอดเรียก
ในช่วงหลังฉันใช้มาตลอดdispatch_get_current_queue()
แต่ดูเหมือนว่าจะเลิกใช้งานใน iOS 6 ขึ้นไป ฉันควรใช้อะไรแทน?
คำตอบ:
รูปแบบของ "เรียกใช้ตามคิวใดก็ตามที่ผู้โทรเปิดอยู่" นั้นน่าสนใจ แต่ท้ายที่สุดก็ไม่ใช่ความคิดที่ดี คิวนั้นอาจเป็นคิวลำดับความสำคัญต่ำคิวหลักหรือคิวอื่น ๆ ที่มีคุณสมบัติแปลก ๆ
วิธีที่ฉันชอบที่สุดคือการพูดว่า "การบล็อกเสร็จสิ้นทำงานบนคิวที่กำหนดการนำไปใช้งานด้วยคุณสมบัติเหล่านี้: x, y, z" และปล่อยให้บล็อกส่งไปยังคิวหนึ่งหากผู้เรียกต้องการการควบคุมมากกว่านั้น ชุดคุณสมบัติทั่วไปที่จะระบุจะเป็น "อนุกรมไม่ reentrant และ async เทียบกับคิวอื่น ๆ ที่แอปพลิเคชันมองเห็นได้"
** แก้ไข **
Catfish_Man ใส่ตัวอย่างไว้ในความคิดเห็นด้านล่างฉันแค่เพิ่มคำตอบของเขา
- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler
{
dispatch_async(self.workQueue, ^{
[self doSomeWork];
dispatch_async(self.callbackQueue, completionHandler);
}
}
นี่เป็นแนวทางที่ไม่ถูกต้องสำหรับ API ที่คุณกำลังอธิบายถึง หาก API ยอมรับบล็อกและบล็อกที่สมบูรณ์เพื่อเรียกใช้ข้อเท็จจริงต่อไปนี้จะต้องเป็นจริง:
"block to run" ควรรันบนคิวภายในเช่นคิวซึ่งเป็นส่วนตัวของ API และด้วยเหตุนี้ทั้งหมดจึงอยู่ภายใต้การควบคุมของ API นั้น ข้อยกเว้นเพียงประการเดียวคือหาก API ประกาศโดยเฉพาะว่าบล็อกจะถูกรันบนคิวหลักหรือหนึ่งในคิวที่ทำงานพร้อมกันทั่วโลก
บล็อกเสร็จควรเสมอจะแสดงเป็น tuple (คิวบล็อก) เว้นแต่สมมติฐานเช่นเดียวกับ # 1 ถือเป็นจริงเช่นบล็อกเสร็จสิ้นจะมีการทำงานในคิวโลกที่รู้จักกัน นอกจากนี้บล็อกการเสร็จสมบูรณ์ควรถูกส่งแบบ async ในคิวที่ส่งผ่าน
สิ่งเหล่านี้ไม่ใช่แค่ประเด็นเกี่ยวกับโวหารเท่านั้น แต่ยังจำเป็นอย่างยิ่งหาก API ของคุณต้องปลอดภัยจากการชะงักงันหรือพฤติกรรมอื่น ๆ ที่อาจจะแขวนคุณไว้จากต้นไม้ที่ใกล้ที่สุดในสักวันหนึ่ง :-)
คำตอบอื่น ๆ นั้นยอดเยี่ยม แต่สำหรับฉันคำตอบนั้นมีโครงสร้าง ฉันมีวิธีการเช่นนี้ใน Singleton:
- (void) dispatchOnHighPriorityNonMainQueue:(simplest_block)block forceAsync:(BOOL)forceAsync {
if (forceAsync || [NSThread isMainThread])
dispatch_async_on_high_priority_queue(block);
else
block();
}
ซึ่งมีสองการอ้างอิงซึ่ง ได้แก่ :
static void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}
และ
typedef void (^simplest_block)(void); // also could use dispatch_block_t
ด้วยวิธีนี้ฉันรวมศูนย์การโทรเพื่อส่งไปยังเธรดอื่น
คุณควรระมัดระวังเกี่ยวกับการใช้งานdispatch_get_current_queue
ตั้งแต่แรก จากไฟล์ส่วนหัว:
แนะนำสำหรับการดีบักและการบันทึกเท่านั้น:
โค้ดจะต้องไม่ตั้งสมมติฐานใด ๆ เกี่ยวกับคิวที่ส่งคืนเว้นแต่ว่าจะเป็นคิวส่วนกลางหรือคิวที่โค้ดได้สร้างขึ้นเอง รหัสต้องไม่ถือว่าการดำเนินการแบบซิงโครนัสไปยังคิวนั้นปลอดภัยจากการหยุดชะงักหากคิวนั้นไม่ใช่คิวที่ส่งคืนโดย dispatch_get_current_queue ()
คุณสามารถทำอย่างใดอย่างหนึ่งจากสองสิ่ง:
ให้อ้างอิงถึงคิวที่คุณโพสต์ไว้ในตอนแรก (หากคุณสร้างผ่านdispatch_queue_create
) และใช้ต่อจากนั้นเป็นต้นไป
ใช้คิวที่ระบบกำหนดผ่านdispatch_get_global_queue
และติดตามว่าคุณกำลังใช้คิวใดอยู่
อย่างมีประสิทธิภาพในขณะที่ก่อนหน้านี้อาศัยระบบเพื่อติดตามคิวที่คุณอยู่คุณจะต้องดำเนินการด้วยตัวเอง
dispatch_get_current_queue()
เพื่อค้นหาว่าคิวใดคืออะไร? บางครั้งโค้ดที่ต้องการทราบว่าคิวใดที่รันอยู่ก็ไม่มีการควบคุมหรือความรู้ใด ๆ ฉันมีโค้ดจำนวนมากที่สามารถ (และควร) ถูกเรียกใช้งานบนคิวพื้นหลัง แต่บางครั้งจำเป็นต้องอัปเดต gui (แถบความคืบหน้า ฯลฯ ) ดังนั้นจึงจำเป็นต้องส่ง Dispatch_sync () ไปยังคิวหลักสำหรับการดำเนินการเหล่านั้น หากอยู่ในคิวหลักแล้ว dispatch_sync () จะล็อกตลอดไป ฉันจะใช้เวลาหลายเดือนในการ refactor รหัสของฉันสำหรับสิ่งนี้
Apple เลิกใช้งานไปแล้วdispatch_get_current_queue()
แต่ทิ้งช่องว่างไว้ที่อื่นดังนั้นเรายังสามารถรับคิวการจัดส่งปัจจุบันได้:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
// Do stuff
}
สิ่งนี้ใช้ได้กับคิวหลักเป็นอย่างน้อย หมายเหตุunderlyingQueue
คุณสมบัตินั้นพร้อมใช้งานตั้งแต่ iOS 8
หากคุณจำเป็นต้องดำเนินการบล็อกการทำให้สมบูรณ์ในคิวเดิมคุณอาจใช้OperationQueue
โดยตรงฉันหมายถึงไม่มี GCD
สำหรับผู้ที่ยังต้องการการเปรียบเทียบคิวคุณสามารถเปรียบเทียบคิวตามป้ายกำกับหรือระบุ ตรวจสอบที่นี่https://stackoverflow.com/a/23220741/1531141
นี่คือคำตอบสำหรับฉัน ดังนั้นฉันจะพูดถึงกรณีการใช้งานของเรา
เรามีเลเยอร์บริการและเลเยอร์ UI (รวมถึงเลเยอร์อื่น ๆ ) ชั้นบริการจะเรียกใช้งานในพื้นหลัง (งานจัดการข้อมูลงาน CoreData การโทรเครือข่าย ฯลฯ ) ชั้นบริการมีคิวการดำเนินการสองสามคิวเพื่อตอบสนองความต้องการของเลเยอร์ UI
เลเยอร์ UI อาศัยเลเยอร์บริการเพื่อทำงานจากนั้นเรียกใช้บล็อกการทำให้สำเร็จ บล็อกนี้สามารถมีรหัส UIKit อยู่ในนั้น กรณีใช้งานง่ายๆคือรับข้อความทั้งหมดจากเซิร์ฟเวอร์และโหลดมุมมองคอลเลกชันใหม่
ที่นี่เรารับประกันว่าบล็อกที่ส่งผ่านไปยังชั้นบริการจะถูกส่งไปตามคิวที่เรียกใช้บริการ เนื่องจาก dispatch_get_current_queue เป็นวิธีที่เลิกใช้แล้วเราจึงใช้ NSOperationQueue.currentQueue เพื่อรับคิวปัจจุบันของผู้โทร หมายเหตุสำคัญเกี่ยวกับคุณสมบัตินี้
การเรียกใช้เมธอดนี้จากภายนอกบริบทของการดำเนินการที่กำลังทำงานอยู่มักจะส่งคืนค่าศูนย์
เนื่องจากเรามักเรียกใช้บริการของเราตามคิวที่ทราบ (คิวที่กำหนดเองและคิวหลัก) สิ่งนี้จึงเหมาะกับเรา เรามีกรณีที่ serviceA สามารถเรียก serviceB ซึ่งสามารถเรียก serviceC ได้ เนื่องจากเราควบคุมว่าจะให้เรียกใช้บริการครั้งแรกจากที่ใดเราจึงทราบว่าบริการที่เหลือจะปฏิบัติตามกฎเดียวกัน
ดังนั้น NSOperationQueue.currentQueue จะส่งคืนหนึ่งในคิวของเราหรือ MainQueue เสมอ
dispatch_get_current_queue()
เลิกใช้งานใน iOS 6 แล้ว? เอกสารไม่ได้พูดอะไรเกี่ยวกับเรื่องนี้