2016-04-27 14 views
0

Ich arbeite an einer Swift-App, die mit externen Binärdateien (über NSTask) interagiert und die Ausgabe als Array von Strings für jede Zeile zurückgibt.Mehrere NSTasks verursachen inkonsistente Ausgabe

Wenn die executeCommand-Funktion mehrere Male aufgerufen wird, beginnen die Befehle, die erwarteten Daten nicht zu liefern.

Im Beispiel Playground unten lese ich diskutil nach Volume-Namen.

Im Debug Gebiet die erste Antwort, die ich bekommen ist:

  • Nicht anwendbar (kein Dateisystem)
  • Macintosh HD
  • Unable Volumen Namen
  • können nicht erhalten Volume-Namen zu erhalten
  • Der Name des Datenträgers konnte nicht abgerufen werden

einfach wieder läuft den Spielplatz Ergebnisse in:

  • Nicht anwendbar (kein Dateisystem)
  • Unable Volume-Namen < zu erhalten - Was geschah mit Mac HD?
  • Unable Volume-Name
  • konnte nicht erhalten Volume-Name
  • konnte nicht erhalten Volume-Namen

    import Cocoa 
    
    func executeCommand(launchPath: String, arguments: [String], additionalDelay: Int=0) -> [String] { 
    
        let outputPipe = NSPipe() 
        var outputArray = [String]() 
    
        let task = NSTask() 
        task.launchPath = launchPath 
        task.arguments = arguments 
        task.standardOutput = outputPipe 
    
        outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() 
    
        NSNotificationCenter.defaultCenter().addObserverForName(NSFileHandleDataAvailableNotification, object: outputPipe.fileHandleForReading , queue: nil) { 
         notification in 
    
         let output = outputPipe.fileHandleForReading.availableData 
         let outputString = String(data: output, encoding: NSUTF8StringEncoding) ?? "" 
    
         outputArray = outputString.componentsSeparatedByCharactersInSet(.newlineCharacterSet()) 
    
         outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() 
    
        } 
    
        task.launch() 
        sleep(UInt32(additionalDelay)) // Additional delay 
        task.waitUntilExit() 
    
        // Remove last empty line from output array. 
        if outputArray.count > 0 { 
         outputArray.removeLast() 
        } 
    
        return outputArray 
    
    } 
    
    
    // Example usage 
    
    
    
    // Output volume name from provided disk identifier 
    func volumeName(identifier: String) -> String { 
        let volumeNameCommand = "/usr/sbin/diskutil info \(identifier) | awk '/Volume Name:/' | sed 's/Volume Name://g'| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'" 
        let volumeNameOutput = executeCommand("/bin/bash", arguments: ["-c", volumeNameCommand]) 
    
        var volumeName = "Unable to obtain volume name" 
    
        if volumeNameOutput.count > 0 { 
         volumeName = volumeNameOutput[0] 
        } 
    
        return volumeName 
    } 
    
    let identifiers = ["/dev/disk0","/dev/disk1","/dev/disk2","/dev/disk3","/dev/disk4"] 
    
    for identifier in identifiers { 
        print(volumeName(identifier)) 
    } 
    

ich wirklich brauchen konsistente Ergebnisse zu erhalten, aber nicht verstehen, wo ich bin falsch machen.

Jede Hilfe würde sehr geschätzt werden!

Antwort

0

Ich glaube, die asynchrone Ausführung von Aufgaben verursachte die inkonsistenten Ergebnisse. Unten ist eine neue Funktion, die wie erwartet funktioniert:

func executeCommand(launchPath: String, arguments: [String]) -> [String] { 

    let task: NSTask = NSTask() 
    let pipe: NSPipe = NSPipe() 

    task.launchPath = launchPath 
    task.arguments = arguments 
    task.standardOutput = pipe 
    task.launch() 
    task.waitUntilExit() 

    let handle = pipe.fileHandleForReading 
    let data = handle.readDataToEndOfFile() 
    let outputString = String(data: data, encoding: NSUTF8StringEncoding) ?? "" 

    var outputArray = [String]() 
    outputArray = outputString.componentsSeparatedByCharactersInSet(.newlineCharacterSet()) 
    return outputArray 

}