2016-06-21 13 views
11

Tôi có một vài bài kiểm tra đơn vị mà tôi muốn kiểm tra xem một cuộc gọi lại có được gọi trên hàng đợi đúng hay không.Kiểm tra xem có đúng hàng đợi công văn trong Swift 3

Trong Swift 2, tôi đã so sánh nhãn của hàng đợi hiện tại với hàng đợi kiểm tra của tôi. Tuy nhiên trong Swift 3 hằng số DISPATCH_CURRENT_QUEUE_LABEL không còn tồn tại nữa.

Tôi đã tìm thấy hàm dispatch_assert_queue. Mà có vẻ là những gì tôi cần, nhưng tôi không chắc chắn làm thế nào để gọi nó.

Swift 2 Mã của tôi:

let testQueueLabel = "com.example.my-test-queue" 
let testQueue = dispatch_queue_create(testQueueLabel, nil) 

let currentQueueLabel = String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))! 
XCTAssertEqual(currentQueueLabel, testQueueLabel, "callback should be called on specified queue") 

Cập nhật:

tôi đã nhầm lẫn do thiếu autocomplete, nhưng nó có thể sử dụng __dispatch_assert_queue:

if #available(iOS 10.0, *) { 
    __dispatch_assert_queue(test1Queue) 
} 

Trong khi điều này làm việc cho các bài kiểm tra đơn vị, nó gây phiền nhiễu dừng toàn bộ quá trình với một EXC_BAD_INSTRUCTION thay vì chỉ thất bại một bài kiểm tra.

+1

Tại sao không đặt điều kiện tiên quyết để kiểm tra trực tiếp cho hàng đợi hoặc thiết lập "cụ thể" vào nó và lấy nó sau này? – KFDoom

+1

Bạn không thể sử dụng setSpecific và getSpecific? src: https://github.com/duemunk/Async/blob/feature/Swift_3.0/AsyncTest/AsyncTests.swift – KFDoom

+0

@KFDoom Không biết về các chức năng đó. Điều đó hoạt động tốt cho các bài kiểm tra đơn vị này! –

Trả lời

9

Trả lời câu hỏi của riêng tôi:

Dựa trên KFDoom's comments, Tôi bây giờ sử dụng setSpecificgetSpecific.

Điều này tạo ra một chìa khóa, đặt nó trên hàng đợi kiểm tra, và sau này, được nó một lần nữa:

let testQueueLabel = "com.example.my-test-queue" 
let testQueue = DispatchQueue(label: testQueueLabel, attributes: []) 
let testQueueKey = DispatchSpecificKey<Void>() 

testQueue.setSpecific(key: testQueueKey, value:()) 

// ... later on, to test: 

XCTAssertNotNil(DispatchQueue.getSpecific(key: testQueueKey), "callback should be called on specified queue") 

Lưu ý rằng không có giá trị liên quan đến việc chủ chốt (loại của nó là Void), tôi m chỉ quan tâm đến sự tồn tại của cụ thể, không phải trong giá trị của nó.

Quan trọng!
Đảm bảo giữ tham chiếu đến khóa hoặc dọn dẹp sau khi bạn sử dụng xong. Nếu không, một khóa mới được tạo có thể sử dụng cùng một địa chỉ bộ nhớ, dẫn đến hành vi lạ. Xem: http://tom.lokhorst.eu/2018/02/leaky-abstractions-in-swift-with-dispatchqueue

3

Một tùy chọn là đặt điều kiện tiên quyết để kiểm tra trực tiếp cho hàng đợi hoặc đặt "cụ thể" trên hàng đợi và truy xuất sau. Hơn nữa, người ta có thể sử dụng setSpecific và getSpecific. Ngoài ra, bạn có thể sử dụng kiểm tra điều kiện tiên quyết nếu bạn đang ở trong hàng đợi để đáp ứng nhu cầu "hiện tại". src:

https://github.com/apple/swift/blob/master/stdlib/public/SDK/Dispatch/Dispatch.swift

+0

liên kết đầu tiên hiện đã bị hỏng. – Sid

3

thử nghiệm dựa trên KFDoom's answer:

import XCTest 
import Dispatch 

class TestQueue: XCTestCase { 

    func testWithSpecificKey() { 
     let queue = DispatchQueue(label: "label") 

     let key = DispatchSpecificKey<Void>() 
     queue.setSpecific(key:key, value:()) 

     let expectation1 = expectation(withDescription: "main") 
     let expectation2 = expectation(withDescription: "queue") 

     DispatchQueue.main.async { 
      if (DispatchQueue.getSpecific(key: key) == nil) { 
       expectation1.fulfill() 
      } 
     } 

     queue.async { 
      if (DispatchQueue.getSpecific(key: key) != nil) { 
       expectation2.fulfill() 
      } 
     } 

     waitForExpectations(withTimeout: 1, handler: nil) 
    } 

    func testWithPrecondition() { 
     let queue = DispatchQueue(label: "label") 

     let expectation1 = expectation(withDescription: "main") 
     let expectation2 = expectation(withDescription: "queue") 

     DispatchQueue.main.async { 
      dispatchPrecondition(condition: .notOnQueue(queue)) 
      expectation1.fulfill() 
     } 

     queue.async { 
      dispatchPrecondition(condition: .onQueue(queue)) 
      expectation2.fulfill() 
     } 

     waitForExpectations(withTimeout: 1, handler: nil) 
    } 

} 
+0

'setSpecific (key:, value:)' là không cần thiết trong trường hợp thứ hai. – Lucien

13

Sử dụng dispatchPrecondition(.onQueue(expectedQueue)), việc thay Swift 3 API cho dispatch_assert_queue() C API.

này được đề cập trong phiên WWDC GCD năm nay: https://developer.apple.com/videos/play/wwdc2016/720/

+0

Điều này yêu cầu macOS 10.12/iOS 10.0, điều đó có đúng không? - Điều này có thể được sử dụng trong một bài kiểm tra đơn vị? –

+0

chính xác.Nó sẽ chấm dứt quá trình nếu điều kiện tiên quyết không thành công, miễn là bạn có thể xử lý nó trong thử nghiệm đơn vị của bạn nó sẽ làm việc cho mục đích đó – das

-1
/* 
Dispatch queue and NSOperations in Swift 3 Xcode 8 
*/ 

protocol Container { 

    associatedtype ItemType 
    var count: Int { get } 
    mutating func pop() 
    mutating func push(item: ItemType) 
    mutating func append(item: ItemType) 
    subscript(i: Int) -> ItemType { get } 
} 

//Generic Function 
struct GenericStack<Element> : Container { 
    mutating internal func push(item: Element) { 
     items.append(item) 
    } 

    mutating internal func pop() { 
     items.removeLast() 
    } 

    var items = [ItemType]() 
    internal subscript(i: Int) -> Element { 
     return items[i] 
    } 

    mutating internal func append(item: Element) { 
     self.push(item: item) 
    } 

    internal var count: Int { return items.count } 
    typealias ItemType = Element 
} 

var myGenericStack = GenericStack<String>() 
myGenericStack.append(item: "Narendra") 
myGenericStack.append(item: "Bade") 
myGenericStack.count 
myGenericStack.pop() 
myGenericStack.count 

//Some NSOperation 
class ExploreOperationAndThread { 

    func performOperation() { 

     //Create queue 
     let queue = OperationQueue() 
     let operation1 = BlockOperation { 
      var count = myGenericStack.count 
      while count > 0 { 
       myGenericStack.pop() 
       count -= 1 
      } 
     } 

     operation1.completionBlock = { 
      print("Operation 1") 
     } 

     let operation2 = BlockOperation { 
      var count = 0 
      while count == 10 { 
       myGenericStack.append(item: "ItemAdded") 
       count += 1 
      } 
     } 

     operation2.completionBlock = { 
      print("Operation 2") 
      print(myGenericStack.items) 
     } 

     //Suppose operation 3 is related to UI 

     let operation3 = BlockOperation { 
      //run on main thread 
      DispatchQueue.main.async { 
       print(myGenericStack.items.count) 
      } 
     } 

     operation3.completionBlock = { 
      print("Operation 3") 
      print(myGenericStack.items.count) 
     } 
     //add operation into queue 
     queue.addOperation(operation3) 
     queue.addOperation(operation1) 
     queue.addOperation(operation2) 
     //Limit number of concurrent operation in queue 
     queue.maxConcurrentOperationCount = 1 
     //add dependancies 
     operation1.addDependency(operation2) 
     operation2.addDependency(operation3) 

     if myGenericStack.items.count == 0 { 
      //remove dependency 
      operation1.removeDependency(operation2) 
     } 
    } 
} 

//Other ways of using queues 
DispatchQueue.global(qos: .userInitiated).async { 
    ExploreOperationAndThread().performOperation() 
} 

DispatchQueue.main.async { 
    print("I am performing operation on main theread asynchronously") 
} 

OperationQueue.main.addOperation { 
    var count = 0 
    while count == 10 { 
     myGenericStack.append(item: "Narendra") 
     count += 1 
    } 
} 

DispatchQueue.main.asyncAfter(deadline: .now() + 1.5 , execute: { 
    ExploreOperationAndThread().performOperation() 
}) 

let queue2 = DispatchQueue(label: "queue2") //Default is serial queue 
queue2.async { 
    print("asynchronously") 
} 
Các vấn đề liên quan