2015-06-08 16 views
15

Tôi đang cố gắng thử nghiệm một ứng dụng dòng lệnh ít minh họa trước khi tích hợp nó vào một ứng dụng lớn hơn. Những gì tôi đang cố gắng làm là tải xuống một số dữ liệu bằng cách sử dụng NSURLSession sử dụng this example. Tuy nhiên, có vẻ như nếu tôi sử dụng các ví dụ được đưa ra trong một ứng dụng dòng lệnh OS X đơn giản thì ứng dụng sẽ thoát trước khi dữ liệu được truy xuất.Sử dụng NSURLSession từ chương trình dòng lệnh Swift

Tôi làm cách nào để tải xuống dữ liệu từ ứng dụng dòng lệnh độc lập bằng NSURLSession? Những gì tôi đã đọc về là sử dụng NSRunLoop tuy nhiên tôi chưa tìm thấy một ví dụ rõ ràng trong Swift vì vậy nếu NSRunLoop thực sự là con đường để đi sau đó bất kỳ ví dụ sẽ được đánh giá cao.

Bất kỳ chiến lược nào khác để tải xuống dữ liệu từ URL cho ứng dụng dòng lệnh Swift cũng được chào đón (vòng lặp vô hạn trong khi?).

+2

Hãy thử thêm 'NSRunLoop. mainRunLoop(). run() 'ở cuối tập tin của bạn ... – nielsbot

+0

Cảm ơn, nó hoạt động. Vì vậy, để xác nhận, điều đó chỉ chạy cho đến khi chương trình bị chấm dứt bên ngoài? Bạn có thể thêm điều đó làm câu trả lời và mọi thông tin bổ sung sẽ được đánh giá cao. Chẳng hạn như a) cách thoát khỏi chương trình b) và một chút thông tin cơ bản về lý do tại sao nó tốt hơn vòng lặp vô hạn. –

+0

có - điều đó sẽ chỉ chạy mãi mãi. – nielsbot

Trả lời

20

Bạn có thể sử dụng semaphore để chặn chuỗi hiện tại và đợi phiên URL của bạn kết thúc.

Tạo semaphore, khởi chạy phiên URL của bạn, sau đó chờ trên semaphore. Từ cuộc gọi lại hoàn thành phiên URL của bạn, hãy báo hiệu semaphore.

Bạn có thể sử dụng cờ chung (khai báo biến boolean dễ bay hơi) và thăm dò ý kiến ​​từ một vòng lặp while, nhưng điều đó ít tối ưu hơn. Đối với một điều, bạn đang đốt chu kỳ CPU không cần thiết.

Dưới đây là một ví dụ nhanh tôi đã sử dụng một sân chơi:

import Foundation 

var sema = DispatchSemaphore(value: 0) 

class Delegate : NSObject, URLSessionDataDelegate 
{ 
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) 
    { 
     print("got data \(String(data: data, encoding: .utf8) ?? "<empty>")"); 
     sema.signal() 
    } 
} 

let config = URLSessionConfiguration.default 
let session = URLSession(configuration: config, delegate: Delegate(), delegateQueue: nil) 

guard let url = URL(string:"http://apple.com") else { fatalError("Could not create URL object") } 

session.dataTask(with: url).resume()  

sema.wait() 
+0

Đây là một giải pháp thực sự tốt.Thực sự cần một khuôn khổ xung quanh ý tưởng này để theo dõi tất cả các ẩn dụ bạn sẽ tạo khi cần thiết. – Tatsh

+0

Có lẽ một khi Swift được hỗ trợ gốc cho các tính năng kiểu "không đồng bộ", điều đó sẽ không cần thiết nữa. – nielsbot

+0

Nếu bạn muốn có giải pháp cấp cao, hãy kiểm tra 'NSOperationQueue' và' NSBlockOperation' – nielsbot

2

Nếu nó chỉ cho mục đích thử nghiệm, bạn có thể tránh sử dụng semaphore nếu bạn cứng mã "thời gian thực hiện" của ứng dụng dòng lệnh của bạn như thế này :

SWIFT 3

//put at the end of your main file 
RunLoop.main.run(until: Date(timeIntervalSinceNow: 15)) //will run your app for 15 seconds only 

này là rất nhanh chóng và bẩn cách để "kích hoạt" các ứng dụng dòng lệnh để chờ các chủ đề khác hoàn tất. Ngoài ra, ứng dụng của bạn sẽ thoát bình thường sau khi hết thời gian chờ mà không cần phải giết hoặc hủy bỏ quá trình ứng dụng một cách rõ ràng.

LƯU Ý:

  1. Bạn có thể thay đổi khoảng thời gian 'timeout' nếu nhiệm vụ kết nối mạng của bạn đòi hỏi nhiều thời gian để hoàn thành.
  2. này 'giải pháp' là quyết định chắc chắn kém nếu bạn muốn cơ chế chờ đợi nghiêm trọng hơn (aka. KHÔNG SỬ DỤNG NÀY TRONG SẢN XUẤT)
+0

có thể 'ngủ (15)' làm cùng một thủ thuật? (trả lời lại từ http://stackoverflow.com/a/40870288/1135503) –

+0

@KentLiau: bạn có giả sử hàm C sleep() không? Nếu vậy, bạn cần phải nhập mô-đun Darwin, nhưng hãy chú ý đến hệ điều hành nền tảng bạn đang chạy mã. – Vexy

1

Hãy thử điều này

let sema = DispatchSemaphore(value: 0) 

let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg")!; 

let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
    print("after image is downloaded"); 
    sema.signal(); // signals the process to continue 
}; 

task.resume(); 
sema.wait(); // sets the process to wait 
Các vấn đề liên quan