在 Swift 应用程序中使用 pipeline() 将 stdout 重定向到 textView (仅在模拟器中运行,而不是在本机中运行)

Kri*_*chu 7 xcode simulator pipe ios swift

我在 Xcode IDE 下使用 Swift 创建了一个适用于 iPhone 的 iOS 应用程序。出于调试目的,我希望将 print (以及 C 代码中的 printf )正常打印到 Xcode 控制台的所有内容重定向到UItextView. 我的代码(主要来自这里)如下:

//
//  ViewController.swift
//  Scroll View Demo
//

//  
//

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var writeButton: UIButton!
    var pipe = Pipe()
    var count = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // dup2() makes newfd (new file descriptor) be the copy of oldfd (old file descriptor), closing newfd first if necessary.
        openConsolePipe()
        print("\npipe started")

    }

    @IBAction func buttonPressed(_ sender: Any) {
        print("\(count). Hello world")
        count += 1
    }
    public func openConsolePipe () {
        dup2(pipe.fileHandleForWriting.fileDescriptor, 
            STDOUT_FILENO)
        // listening on the readabilityHandler
        pipe.fileHandleForReading.readabilityHandler = {
         [weak self] handle in
        let data = handle.availableData
        let str = String(data: data, encoding: .ascii) ?? "<Non-ascii data of size\(data.count)>\n"
        DispatchQueue.main.async {
            self?.textView.text += str
        }
      }
    }

}
Run Code Online (Sandbox Code Playgroud)

该代码在物理设备和虚拟 iPhone 上以模拟模式运行。但是当我使用 Xcode 剪切线本地运行它时,pipe() 不起作用。我目前不知道为什么 pipeline() 在独立应用程序中不起作用。

Kri*_*chu 7

使示例最终工作的代码更改是将 stdout 的文件句柄修改为无缓冲的 (setvbuf(stdout, nil, _IONBF, 0)):

//
//  ViewController.swift
//  Scroll View Demo
//

//  
//



import UIKit

class ViewController: UIViewController {


@IBOutlet weak var textView: UITextView!
@IBOutlet weak var writeButton: UIButton!
var pipe = Pipe()
var count = 0

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    // dup2() makes newfd (new file descriptor) be the copy of oldfd (old file descriptor), closing newfd first if necessary.
    openConsolePipe()
    print("\npipe started")

}

@IBAction func buttonPressed(_ sender: Any) {
    print("\(count). Hello world")
    count += 1
}
public func openConsolePipe () {
    setvbuf(stdout, nil, _IONBF, 0) //<--------- !
    dup2(pipe.fileHandleForWriting.fileDescriptor, 
        STDOUT_FILENO)
    // listening on the readabilityHandler
    pipe.fileHandleForReading.readabilityHandler = {
     [weak self] handle in
    let data = handle.availableData
    let str = String(data: data, encoding: .ascii) ?? "<Non-ascii data of size\(data.count)>\n"
    DispatchQueue.main.async {
        self?.textView.text += str
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是因为,当应用程序与 Xcode 断开连接运行时,stdout 会被重定向到类似 /dev/null 的内容,并且缓冲设置为“buffered”,因此永远不会出现在 pipeline() 中。将其设置为无缓冲可以使事情正常进行。