2016-01-15 11 views
9

Vì vậy, tôi có một ứng dụng kích hoạt một loạt các sự kiện không đồng bộ và sau đó ghi kết quả vào bộ đệm. Vấn đề là tôi muốn bộ đệm để được ghi vào đồng bộ (trong các chủ đề mà sinh ra các quá trình không đồng bộ)Swift 2 - iOS - Công văn trở lại chủ đề ban đầu

đang skeleton là như vậy

let Session = NSURLSession.sharedSession() 
let TheStack = [Structure]() 
//This gets called asynchronously, e.g. in threads 3,4,5,6,7 
func AddToStack(The Response) -> Void { 
    TheStack.insertAt(Structure(The Response), atIndex: 0)) 
    if output.hasSpaceAvailable == true { 
     // This causes the stream event to be fired on mutliple threads 
     // This is what I want to call back into the original thread, e.g. in thread 2 
     self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable) 
    } 
} 

// This is in the main loop, e.g. thread 2 
func stream(aStream: NSStream, handleEvent: NSStreamEvent) { 

    switch(NSStreamEvent) { 

     case NSStreamEvent.OpenCompleted: 
      // Do some open stuff 
     case NSStreamEvent.HasBytesAvailable: 
      Session.dataTaskWithRequest(requestFromInput, completionHandler: AddToStack) 
     case NSStreamEvent.HasSpaceAvailable: 
      // Do stuff with the output 
     case NSStreamEvent.CloseCompleted: 
      // Close the stuff 
    } 
} 

Vấn đề là các chủ đề mà các cuộc gọi là dataTaskWithRequest là trong thread, nói, 3. xử lý hoàn thành cháy trong nhiều chủ đề khác nhau và nguyên nhân case NSStreamEvent.HasSpaceAvailable: để được chạy trong chủ đề 3, cộng với tất cả các chủ đề mà họ tồn tại.

Câu hỏi của tôi là: Làm thế nào để làm cho nó để self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable) là được gọi trong chuỗi 3, hoặc chủ đề ban đầu để ngăn chặn sự vấp ngã này của nhau trong pha đầu ra.

Cảm ơn trước!

LƯU Ý: Các chủ đề có chứa các xử lý đầu vào/đầu ra đã được tạo ra với NSThread.detachNewThreadSelector

+2

Làm cách nào để tạo (các) hàng đợi của riêng bạn và chuyển hàng đợi đó đến nhà văn của bạn? (Tôi nói "xếp hàng" vì bạn đã gắn thẻ bằng gcd.) –

+1

Tôi đã nghĩ về việc đó khoảng 5 phút trước khi tôi phải nghỉ việc. Tạo luồng/hàng đợi và đưa tất cả đầu ra đến đó. Bằng cách đó, ngay cả khi có nhiều chủ đề gọi trong họ không phải là tất cả cố gắng để thực hiện cùng một lúc. Tôi tắt cho đến thứ ba bây giờ vì vậy nếu đó là con đường tôi đi tôi sẽ cho bạn biết làm thế nào nó đi – Ajwhiteway

+0

Tôi đã có một NSThread tạo ra bởi NSThread.detachNewThreadSelector. Đây là chủ đề mà tôi cần gọi lại. Tôi lo sợ việc gửi đi có thể làm cho vấn đề trở nên tồi tệ hơn (các luồng đóng trước khi mọi thứ kết thúc) – Ajwhiteway

Trả lời

6

Alright, cho người xem tò mò tôi, với sự giúp đỡ từ bình luận cho câu hỏi tôi đã tìm ra cách để làm những gì tôi ban đầu được hỏi trong câu hỏi (có hay không điều này cuối cùng được viết lại để sử dụng GCD là một câu hỏi khác)

Giải pháp (với phạm vi tăng nhẹ vào mã) là sử dụng performSelector với một chuỗi cụ thể.

final class ArbitraryConnection { 

internal var streamThread: NSThread 

let Session = NSURLSession.sharedSession() 
let TheStack = [Structure]() 
//This gets called asynchronously, e.g. in threads 3,4,5,6,7 
func AddToStack(The Response) -> Void { 
    TheStack.insertAt(Structure(The Response), atIndex: 0)) 
    if output.hasSpaceAvailable == true { 
     // This causes the stream event to be fired on multiple threads 
     // This is what I want to call back into the original thread, e.g. in thread 2 

     // Old way 
     self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable) 
     // New way, that works 
     if(streamThread != nil) { 
      self.performSelector(Selector("startoutput"), onThread: streamThread!, withObject: nil, waitUntilDone: false) 
     } 
    } 
} 

func open -> Bool { 
    // Some stuff 
    streamThread = NSThread.currentThread() 
} 


final internal func startoutput -> Void { 
    if(output.hasSpaceAvailable && outputIdle) { 
     self.stream(self.output, handleEvent: NSStreamEvent.HasSpaceAvailable) 
    } 
} 
// This is in the main loop, e.g. thread 2 
func stream(aStream: NSStream, handleEvent: NSStreamEvent) { 

    switch(NSStreamEvent) { 

     case NSStreamEvent.OpenCompleted: 
      // Do some open stuff 
     case NSStreamEvent.HasBytesAvailable: 
      Session.dataTaskWithRequest(requestFromInput, completionHandler: AddToStack) 
     case NSStreamEvent.HasSpaceAvailable: 
      // Do stuff with the output 
     case NSStreamEvent.CloseCompleted: 
      // Close the stuff 
    } 
} 
} 

Vì vậy, hãy sử dụng performSelector trên đối tượng có bộ chọn và sử dụng nút onThread để cho biết chuỗi cần chuyển đến. Tôi kiểm tra cả trước khi thực hiện chọn và trước khi thực hiện cuộc gọi để đảm bảo rằng đầu ra có dung lượng trống (đảm bảo rằng tôi không tự mình đi qua)

+0

Tôi sẽ gắn bó với 'performSelector', vì nó kết thúc tốt đẹp GCD, và giải quyết các câu hỏi hóc búa xung quanh việc gửi đi từ các hàng đợi giống nhau hoặc khác nhau. Quan tâm là 'waitUntilDone: false', mà tôi thường thích là' true' để đảm bảo trình tự hoạt động đúng đắn. – SwiftArchitect

+0

Vâng, tôi đã kết thúc dự án để thử nghiệm với 'performSelector' vẫn đang được sử dụng. Bởi vì cách sinh sản này, thường chỉ có một cho mỗi luồng ('dataTaskWithRequest' xử lý điều đó). Vì vậy, bằng cách làm cho nó 'false' tôi cho phép các chủ đề được xóa lên một khi dữ liệu đã được thêm vào hàng đợi cho bộ đệm. Vẫn phải trải qua một số thử nghiệm để đảm bảo rằng mọi thứ đang giữ lại với nhau khi được đưa vào dự án lớn hơn. – Ajwhiteway

+0

Bạn dường như có toàn quyền kiểm soát! Kinh nghiệm của tôi với 'performSelector' và' performBlock' là tôi thường hối tiếc tiết kiệm mili giây ở đây và ở đó, và phải hoàn nguyên về 'waitUntilDone' và' performBlockAndWait' để có độ mạnh và khả năng dự đoán. – SwiftArchitect

1

Nó sẽ không cho phép tôi nhận xét về chủ đề ở trên (đây là những gì tôi nhận được để rình rập), nhưng một điều cần lưu ý là mã hiện tại của bạn có thể bế tắc giao diện người dùng của bạn nếu bạn sử dụng waitUntilDone hoặc performBlockAndWait.

Nếu bạn đi tuyến đường đó, bạn cần phải chắc chắn rằng bạn không gọi nó từ mainThread hoặc có trường hợp dự phòng sinh ra một chuỗi mới.

+0

Đây là một điểm tốt mà tôi chưa rõ ràng xử lý trong mã của tôi, trong trường hợp của tôi xử lý hoàn thành 'dataTaskWithRequest' không bao giờ nên kết thúc bên trong thread GUI chính. Trong mọi trường hợp, một điểm tốt. Vì bạn là người duy nhất không phải là chính tôi để trả lời câu hỏi, hãy tận hưởng phần thưởng thưởng! – Ajwhiteway

Các vấn đề liên quan