4

I have redirected NSLog to a file using the macros.

But I couldn't find a stable way in swift to do that.

As of now I am doing a workaround

I define the following method so whenever I call print in the file it comes here and I write that to a file.

func print(log:String!) {
        if let logg = log {
            DeveloperConsoleManager.sharedInstance.writeOnConsoleLog(logg)
        }
    }

But problems with this approach are

1.I will get Extra Argument in Call If I do like below

print("some comments",Obj1,Obj2)

so I have to use like this

print("some comments \(Obj1) \(Obj2)")

2.I will get error like Cannot convert value of type '[AnyObject]' to expected argument type 'String!' If I try to print an object directly

print(obj)

so I have to call the description method of the object

print(obj.description)

3.I have to include the function definition that I have quoted above wherever I want this functionality But in the case of NSLog its globally defined in one place

so Now I am looking for a stable solution to redirect the contents of print in swift to a file

so I can use print as I do normally in swift

Update:

I tried overriding the print but I got Method does not override any method from its superclass

Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241

2 Answers2

7

First, overriding NSLog with a macro is really bad approach. Just use a different function name and use that. Overriding print is even more fragile. Just name it something else. When someone sees NSLog or print in the code, it shouldn't be a trick.

That said, it'll generally work within a given module, as long as you give it the right signature:

public func print(items: Any..., separator: String = "", terminator: String = "\n")

(EDIT: Fixed up the signature to be very explicit on exactly how print does it, rather than just showing the docs.)

You didn't use varargs syntax (...) in your function, which is why it doesn't accept multiple parameters. And if you want it to accept non-Strings (like obj) then you have to accept Any, not just String.

If you just make your own printlog function (or whatever you want to call it), then of course you can use whatever signature is convenient, but if you're going to overload print, you'll need to match its signature and functionality.

Here's the full implementation. This is a terrible way to do it. You should not override print. But this is how Swift allows it to be done (spread across three files just to demonstrate that it's working):

main.swift:

func print(items: Any..., separator: String = "", terminator: String = "\n") {
    Swift.print("My print is printing \(items)", separator: separator, terminator: terminator)
}

print("In main!")
file1print()
file2print()

file1.swift:

func file1print() {
    print("file1!") // Calls our print
}

file2.swift:

func file2print() {
    print("file2!") // Calls our print
}

Again, this is a horrible idea. It is far better, flexible, and clearer to just create a new function. But Swift definitely can do it.

As a note, if your real goal is just to write stdout or stderr to a file, there's no need to override print or NSLog this way. Just reopen your stdout and/or stderr. For example:

let path: NSString = ...;
freopen(path.UTF8String, "a+", stderr)

That would redirect stderr. Use stdout to get stdout. This will work for anything that prints to stdout/err, no matter what module does it.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • How to create a global function like print ? any ideas ? probably create a category of super class that all classes acquire and call that right ! – Durai Amuthan.H Feb 22 '16 at 15:46
  • Put it outside any class or struct. They're called "free functions." – Rob Napier Feb 22 '16 at 15:57
  • My idea is somehow override the print in swift and stick with that... I tried to override like `override func print(_: Any..., separator: String, terminator: String)` i get Method does not override any method from its superclass...If you could guide me to achieve this it'd be helpful a lot. – Durai Amuthan.H Feb 22 '16 at 16:10
  • Don't use `override`. You're just replacing it in this module or any module that imports this module. Keep in mind that when it's missing (for instance in a module that doesn't import this one), you'll get no warning about that. The other `print` will be found instead. That's the problem with using the same name. – Rob Napier Feb 22 '16 at 16:22
  • 1
    Just once for the module. By default its access level is internal. – Rob Napier Feb 22 '16 at 17:03
  • the print function can't be used like free function and I can't put the function definition in one class and inherit in all the places because Multiple inheritance problem will come.so I have to copy paste the print function in all the places I want like appdelegate,viewcontroller ...etc.. – Durai Amuthan.H Feb 22 '16 at 17:26
  • How to call free functions of swift in Objective C ? I marked the free function with public also but I couldn't access it in the Objective C. – Durai Amuthan.H Jun 17 '16 at 14:46
  • @DuraiAmuthan.H Make them static methods inside of a class that ObjC can see. Free functions are not exported from Swift to ObjC. – Rob Napier Jun 17 '16 at 14:53
  • I put that inside the function also but As I am using varargs in the function it is not accessible I guess public func print(logs:AnyObject!...) – Durai Amuthan.H Jun 17 '16 at 15:13
  • 1
    Swift methods that include variadics cannot be exposed to ObjC. See https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID35 – Rob Napier Jun 17 '16 at 16:27
2

If I dare go off at a tangent...

The safest way to redirect NSLog is to redirect its output rather than trying to catch people providing it with input.

The answer to How to redirect STDOUT to a NSTextView? is an appropriate place to start — NSPipe, NSFileHandle and dup2 are all also available on iOS.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Tommy
  • 99,986
  • 12
  • 185
  • 204
  • For *NSLog* its `stderr` but for `print` in swift ... is it `stderr` too ? – Durai Amuthan.H Feb 23 '16 at 08:47
  • 1
    Despite Apple being unwilling to specify more than "an appropriate output", I _think_ `print` currently and empirically prints to `stdout`. – Tommy Feb 23 '16 at 14:41