Swift cannot output when using NSTimer

2019-07-07 19:54发布

问题:

I tried output to STDOUT every second by using NSTimer.

I wrote the following code and saved it as sample.swift.

#!/usr/bin/swift

import AppKit

class Foo : NSObject {
  override init() {
    super.init()
    NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "bar", userInfo: nil, repeats: true)
  }

  func bar() {
    print("buz")
  }
}

let h = Foo()

// Output successful
// while true {
//   print("Foo!")
// }

NSRunLoop.mainRunLoop().run()

Then, I executed the following command and can see buz.

okada@iyokan$ ./sample.swift
buz
buz
buz
buz

So, I executed the following command but I cannot see any buz.

okada@iyokan$ ./sample.swift > sample.log # wait 5 seconds
okada@iyokan$ cat sample.log
okada@iyokan$ 

By the way, I tried while loop version (activated comment out the above code) then I could get buz by two procedures.

Why I could not get any buz? Please teach me.

回答1:

That is a "normal" behaviour of the stdio library. A file descriptor can be "buffered", which means that the result of all printf() and other output operations goes to an internal buffer first. When that buffer reaches a certain size (e.g. 8KB), its contents is written to the actual file.

There are three modes: "unbuffered" (all output is written to the file immediately), "line buffered" (output is collected until a newline characters is printed), and "fully buffered".

According to Is stdout line buffered, unbuffered or indeterminate by default?:

Unix convention is that stdin and stdout are line-buffered when associated with a terminal, and fully-buffered (aka block-buffered) otherwise.

This explains why you see the output of each print operation immediately when the output goes to the terminal, but not when output is redirected to a file.

With

print("buz")
fflush(stdout)

you can force the output to be written to the file immediately. Alternatively, you can set standard output into line buffering mode by calling

setlinebuf(stdout)

before anything is printed.