2015-06-08 23 views
15

Próbuję przetestować małą aplikację wiersza poleceń proof-of-concept przed zintegrowaniem jej z większą aplikacją. Próbuję pobrać niektóre dane przy użyciu NSURLSession, używając this example. Wygląda jednak na to, że jeśli użyję przykładów podanych w prostej aplikacji wiersza poleceń systemu OS X, aplikacja wyjdzie przed pobieraniem danych.Używanie NSURLSession z programu wiersza poleceń Swift

Jak mogę pobrać dane z autonomicznej aplikacji wiersza poleceń przy użyciu NSURLSession? Przeczytałem o tym, że używam NSRunLoop, ale nie znalazłem jeszcze wyraźnego przykładu w Swift, więc jeśli NSRunLoop jest właściwie drogą do zrobienia, wtedy każdy przykład zostanie doceniony.

Wszystkie inne strategie pobierania danych z adresu URL dla aplikacji wiersza poleceń Swift są również mile widziane (nieskończona pętla?).

+2

spróbuj dodać 'NSRunLoop. mainRunLoop(). run() 'na końcu pliku ... – nielsbot

+0

Dzięki, że działa. Tak więc, aby potwierdzić, że działa aż do zakończenia programu na zewnątrz? Możesz dodać to jako odpowiedź i wszelkie dodatkowe informacje będą mile widziane. Takich jak a) jak wyjść programowo b) i trochę informacji z tła, dlaczego jest lepszy niż nieskończona pętla while. –

+0

tak - to będzie działać wiecznie. – nielsbot

Odpowiedz

20

Możesz użyć semafora, aby zablokować bieżący wątek i poczekać na zakończenie sesji URL.

Utwórz semafor, uruchom sesję URL, a następnie poczekaj na semafor. Od wywołania zwrotnego sesji URL, sygnalizuj semafor.

Można użyć flagi globalnej (zadeklarować zmienną zmienną binarną) i odpytywać od pętli while, ale jest to mniej optymalne. Po pierwsze, niepotrzebnie nagrzewasz cykle procesora.

Oto krótki przykład zrobiłem używając Playground:

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

To jest naprawdę dobre rozwiązanie.Naprawdę potrzebne są ramy wokół tego pomysłu, aby śledzić wszystkie semafory, które utworzysz w razie potrzeby. – Tatsh

+0

Prawdopodobnie kiedyś Swift uzyskał natywne wsparcie dla funkcji typu "asynchronicznego", co nie będzie już konieczne. – nielsbot

+0

Jeśli chcesz rozwiązania wysokiego poziomu, sprawdź 'NSOperationQueue' i' NSBlockOperation' – nielsbot

2

Jeśli to tylko do celów testowych, można uniknąć semafora wykorzystanie jeśli kod ciężko „czas realizacji” od linii aplikacji polecenia jak ta :

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 

to bardzo szybkie i brudne sposób, aby "włączyć" aplikacje linii poleceń, aby czekać na zakończenie innych wątków. Poza tym aplikacja wyłączy się normalnie po wygaśnięciu limitu czasu, bez konieczności jednoznacznego zabijania lub anulowania procesu aplikacji.

UWAGA:

  1. Można zmieniać „czas oczekiwania” okres, jeśli zadania sieciowe wymagają więcej czasu, aby zakończyć.
  2. To 'rozwiązanie' jest zdecydowanie słaba decyzja, czy chcesz bardziej poważny mechanizm oczekiwania (aka. NIE wykorzystuje to w PRODUKCJI)
+0

może "spać (15)" zrobić tę samą sztuczkę? (ponowna odpowiedź z http://stackoverflow.com/a/40870288/1135503) –

+0

@KentLiau: czy przyjmiesz funkcję C sleep()? Jeśli tak, musisz zaimportować moduł Darwin, ale pamiętaj o systemie operacyjnego, na którym uruchamiasz kod. – Vexy

1

Spróbuj

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 
Powiązane problemy