How can I output to STDERR with Swift? - macos

I'm trying to make a command line tool for OS X with Xcode 6 and the new Swift language. How can I send output to stderr? Is this done with println?

For Swift 4.x:
import Darwin
fputs("hello from libc\n", stderr)

Here is a Swift 3 snippet modified from https://gist.github.com/algal/0a9aa5a4115d86d5cc1de7ea6d06bd91.
import Foundation
var standardError = FileHandle.standardError
extension FileHandle: TextOutputStream {
public func write(_ string: String) {
let data = Data(string.utf8)
self.write(data)
}
}
print("I am printed to stderr", to: &standardError)

May be a better way to do it, but you can use NSFileHandle:
import Foundation
// Create a file handle to work with
let stderr = NSFileHandle.fileHandleWithStandardError()
// Build up a string; whatever you want
let stuff = "something"
let something = "I'm a string with \(stuff) in it\n"
// Write it
stderr.writeData(something.dataUsingEncoding(NSUTF8StringEncoding))

Not really a separate answer, but building on top of Rob Napier's answer, we can create a stderr like object so that there is not much to change when Apple comes around to providing stderr as an OutputStreamType:
import Foundation
class StandardErrorOutputStream: OutputStreamType {
func write(string: String) {
let stderr = NSFileHandle.fileHandleWithStandardError()
stderr.writeData(string.dataUsingEncoding(NSUTF8StringEncoding))
}
}
var mx_stderr = StandardErrorOutputStream()
println("on-stdout")
println("on-stderr", &mx_stderr)
EDIT: As of 8/26/2015, Xcode 7 Beta 6, you need the toStream: parameter name, like so:
println("on-stderr", toStream:&mx_stderr)

Swift 4, similar to Ryan's solution but instead of extending the FileHandle, created a new struct which also lets you create a StdErr specific class and avoids the global.
struct StandardErrorOutputStream: TextOutputStream {
let stderr = FileHandle.standardError
func write(_ string: String) {
guard let data = string.data(using: .utf8) else {
fatalError() // encoding failure: handle as you wish
}
stderr.write(data)
}
}
Usage example:
do {
try somethingThatMightFail()
} catch let error {
var errStream = StandardErrorOutputStream()
print("\(error)", to: &errStream)
exit(EXIT_FAILURE)
}

Here are three different methods of increasing complexity:
Compliments of Erica Sadun at http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/:
public struct StderrOutputStream: OutputStreamType {
public mutating func write(string: String) {
fputs(string, stderr)
}
}
public var errStream = StderrOutputStream()
debugPrint("Hello", toStream: &errStream) // prints with new line
For a slightly different method using NSFileHandle.fileHandleWithStandardError, see: http://crunchybagel.com/building-command-line-tools-with-swift/ in the section titled: Writing to stdout / stderr, but this method does not use Swift's print library function.
And for a really crazy ride, check out the method offered by rosettacode.org using NSOutputStream at https://www.rosettacode.org/wiki/Hello_world/Standard_error#Swift:
let out = NSOutputStream(toFileAtPath: "/dev/stderr", append: true)
let err = "Goodbye, World!".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
out?.open()
let success = out?.write(UnsafePointer<UInt8>(err!.bytes), maxLength: err!.length)
out?.close()
if let bytes = success {
print("\nWrote \(bytes) bytes")
}

Xcode 13.2+ and Swift 5.5+
Model:
class StandardError: TextOutputStream {
func write(_ string: String) {
try! FileHandle.standardError.write(contentsOf: Data(string.utf8))
}
}
Usage:
var standardError = StandardError()
print("Error!", to: &standardError)

A condensed and modernized version of #RobNapiers suggested solution:
"A line of text"
.data(using: .utf8)
.map(FileHandle.standardError.write)

Adding to the pile of answers:
func printStderr(_ items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items
.map { String(describing: $0) }
.joined(separator: separator) + terminator
FileHandle.standardError.write(output.data(using: .utf8)!)
}
// Usage
let answer = 42
printStderr("The answer is", answer)

Related

didChangeAutomaticCapitalizationNotification not triggered

What am I doing wrong? I don't get this notification. I have this function:
#objc func onAutocorrection (_ notification: Foundation.Notification) {
Swift.print("\(notification)")
}
later in the same class I do use it as follows:
NotificationCenter.default.addObserver(
self,
selector: #selector(onAutocorrection(_:)),
name: NSSpellChecker.didChangeAutomaticCapitalizationNotification,
object: nil)
The addObserver is executed, but the function is never called even when the application is capitalising in an NSTextView.
Why? Many thanks in advance!
It looks like I misunderstood the notification. It is not meant to be triggered when automatic capitalisation happens but when the systems preference of your Mac is changing.
See the comment of ever helpful Willeke and see Notification of autocorrect
In order to get to the intended result of reacting to autocapitalisation did I implement this function in the NSTextViewDelegate:
public func textView(_ view: NSTextView, didCheckTextIn range: NSRange, types checkingTypes: NSTextCheckingTypes, options: [NSSpellChecker.OptionKey : Any] = [:], results: [NSTextCheckingResult], orthography: NSOrthography, wordCount: Int) -> [NSTextCheckingResult] {
if !range.contains(0){
return results
}
var newResult = [NSTextCheckingResult]()
for result in results {
if let textToChange = view.string[range].components(separatedBy: " ").first, let replacement = result.replacementString?.components(separatedBy: " ").first {
let firstLetterCap = textToChange.capitalizingFirstLetter()
if replacement == firstLetterCap {
continue //don't add to results
}
}
newResult.append(result)
}
return newResult
}
This function will prevent that the first character will be capitalised.
Ultimately, I check whether the capitalised version of the first word of the range that must include position "0" is equal to the first word of the replacement string. And if it is then I remove that result/suggestion from the result list.

Reusable XCTests for several products

I need UI tests for XCode project that is a platfrom for several products.
It means that some elements are custom for some products. For instance, they can have different colors, text styles, etc. from product to product, or the same element could be visible for one project, but hided for another one.
How can I configure my XCode UI tests to make them reusable for various products? I understand I need different schemas. But what about visability elements, for example? It seems I need to check it inside the UI test code? But I think it would be better to use any config file. Am I right? Does anyone have any ideas? I'd be grateful for all advices.
I recommend building out a suite of test helpers that you use in each of your products. These are generic, parameterized functions, such as logging a user in or adding an item to the shopping cart. Instead of hard coding your UI element representations in these helpers, parameterize the inputs. Then you can use them over and over.
func addItemToCart(named: String, saveButtonName: String)
func login(username: String, password: String, submitButtonText: String)
func tapTableCell(imageNamed: String)
Once you create a basic scaffolding for navigation you can move on to assertion helpers. Leaving the complex logic in the helpers enables you to reuse them and keep your product-specific tests lean and readable.
func assertCurrentScreen(named: String)
func assertHighlightedCell(colorNamed: String)
func assertCartTotal(cents: String, containerIdentifier: String)
For all of these functions, I recommend adding two default parameters at the end to note the callers file and line number. If you make any custom assertions you can then pass these references in to show your failure at the callers line, not the helpers.
func assertScreen(titled: String, file: StaticString = #file, line: UInt = #line) {
if !XCUIApplication().navigationBars[titled].exists {
XCTFail("Item was not added to cart.", file: file, line: line)
}
}
I am using a function at the beginning of each test.
class SomeTestsClass: XCTestCase {
func testSomeTest() {
var externalConfigVariable_1 = "value for defult test"
var externalConfigVariable_2 = "value for defult test"
// here You use the external config to override
// the default test logc
if let testConfig = getConfig(for: self.name) {
// read config parameters here
externalConfigVariable_1 = testConfig["test_var_1"]
externalConfigVariable_2 = testConfig["test_var_2"]
// ..........
}
// use the variables as You like
// ......
}
}
extension XCTestCase {
public func getConfig(for name: String?) -> [String: Any]? {
let nameComponents = name?.replacingOccurrences(of: "-", with: "").replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "").components(separatedBy: " ")
if let fileName = nameComponents?.last {
let testBundle = Bundle(for: type(of: self))
guard let path = testBundle.url(forResource: fileName, withExtension: "JSON") else {
return nil
}
if let data = try? Data(contentsOf: path) {
if let testConfig = (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)) as? [String: Any] {
return testConfig
}
}
}
return nil
}
}
Here is an example JSON:
{
"test_var_1": "Some var",
"test_var_2": "Some other var"
}

Swift 2 to swift 3 conversion Midi Input

I'm hoping someone may be able to help i'm using Xcode 8 and swift 3
I have a playground file Xcode 7 swift 2 that involves a Midi callback for Midi Input everything works fine in 7
I tried a conversion to 8 and it brought up errors regarding memory and a few name changes mostly of what i believe to be non serious i also redefined the infinite loop using PlaygroundSupport
However the error i cannot get over involves MyMIDIReadProc at
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
The error says
Cannot convert value of type '(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void' to expected argument type 'MIDIReadProc' (aka '#convention(c) (UnsafePointer, Optional>, Optional>) -> ()')
My understanding is that it needs a #convention(c) wrapper of some description inserted. I think i'm on the right track because you can wrap a function but my knowledge of where to put it has run out. Again i was hoping some one might be able to advise
Thanks for reading
apologies for any bad language as i'm self taught
Here is the original Xcode 7 code
import Cocoa
import CoreMIDI
import XCPlayground
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.memory;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(COpaquePointer(srcConnRefCon)).memory;
print("MIDI Received From Source: \(getDisplayName(srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
// bytes mirror contains all the zero values in the ridiulous packet data tuple
// so use the packet length to iterate.
var i = packet.length;
for (_, attr) in bytes.enumerate()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
--i;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).memory;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
// Keep playground running
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;
And here is the Xcode 8 code converted
var str = "Hello, playground"
import Cocoa
import CoreMIDI
import XCPlayground
import PlaygroundSupport
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.pointee;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
print("MIDI Received From Source: \(getDisplayName(obj: srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
var i = packet.length;
for (_, attr) in bytes.enumerated()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
i -= 1;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).pointee;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
PlaygroundPage.current.needsIndefiniteExecution = true
Pointer types are drastically changed in Swift 3. Many C-based APIs' signatures are changed accordingly.
Following those changes manually would be painful. You can make Swift work for you, with a little modification.
Try changing the function header:
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
to a closure declaration:
let MyMIDIReadProc: MIDIReadProc = {pktList, readProcRefCon, srcConnRefCon in
Swift infers argument types perfectly in this style.
You may need to fix pointer type conversion:
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
to something like this:
//I'm not sure using `!` is safe here...
let srcRef: MIDIEndpointRef = UnsafeMutablePointer(srcConnRefCon!).pointee
(By the way, the equivalent part in your Xcode 7 code is a little bit redundant. You have no need to use intermediate COpaquePointer there.)
In Swift 3, pointers cannot be nil, and nullable pointers are represented with Optionals. You may need many other fixes to work with C-based APIs in Swift 3.
OOPer is pointing (ahem) you in the right direction. Here is a blog post on using Swift 3 Core MIDI along with a working github repo.
Assuming that you're working with CoreMIDI 1.3 or later, you may have more luck using MIDIInputPortCreateWithBlock instead of MIDIInputPortCreate.
This method takes a Swift block as a parameter instead of requiring an #convention(c) function reference, making it more amenable to use within methods belonging to Swift classes, e.g.:
public func midiReadBlock(ptr: UnsafePointer<MIDIPacketList>, _: UnsafeMutableRawPointer?) -> Void {
let list: MIDIPacketList = ptr.pointee
...
}
You may also find these two extensions useful.
This one (derived from here) allows you to iterate directly over a MIDIPacketList using for pkt in list:
extension MIDIPacketList: Sequence {
public func makeIterator() -> AnyIterator<MIDIPacket> {
var iterator: MIDIPacket?
var nextIndex: UInt32 = 0
return AnyIterator {
nextIndex += 1
if nextIndex > self.numPackets { return nil }
if iterator != nil {
iterator = withUnsafePointer(to: &iterator!) { MIDIPacketNext($0).pointee }
} else {
iterator = self.packet;
}
return iterator
}
}
}
and this one adds a method to a MIDIPacket to extract the contents as a [UInt8] instead of having to use the really broken tuple syntax:
extension MIDIPacket {
public var asArray: [UInt8] {
let mirror = Mirror(reflecting: self.data)
let length = Int(self.length)
var result = [UInt8]()
result.reserveCapacity(length)
for (n, child) in mirror.children.enumerated() {
if n == length {
break
}
result.append(child.value as! UInt8)
}
return result
}
}

Pass CSV file to Swift 2 File for UI Automation Testing

Hi i am absolute beginner to the swift and Xcode tool. I am trying to Test application through UI Testing bundle introduced from Xcode 7+. I want to migrate my hardcoded data from scripts to cvs file. please help.
currently i have created a class csvScanner but it is showing Argument labels(contentsOfFile:,encoding :,error) error in code below
import Foundation
class CSVScanner {
class func debug(string:String){
print("CSVScanner: \(string)")
}
class func runFunctionOnRowsFromFile(theColumnNames:Array<String>, withFileName theFileName:String, withFunction theFunction:(Dictionary<String, String>)->()) {
if let strBundle = NSBundle.mainBundle().pathForResource(theFileName, ofType: "csv") {
var encodingError:NSError? = nil
if let fileObject = NSString(contentsOfFile: strBundle, encoding: NSUTF8StringEncoding, error: &encodingError){
var fileObjectCleaned = fileObject.stringByReplacingOccurrencesOfString("\r", withString: "\n")
fileObjectCleaned = fileObjectCleaned.stringByReplacingOccurrencesOfString("\n\n", withString: "\n")
let objectArray = fileObjectCleaned.componentsSeparatedByString("\n")
for anObjectRow in objectArray {
let objectColumns = anObjectRow.componentsSeparatedByString(",")
var aDictionaryEntry = Dictionary<String, String>()
var columnIndex = 0
for anObjectColumn in objectColumns {
aDictionaryEntry[theColumnNames[columnIndex]] = anObjectColumn.stringByReplacingOccurrencesOfString("\"", withString: "", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
columnIndex++
}
if aDictionaryEntry.count>1{
theFunction(aDictionaryEntry)
}else{
CSVScanner.debug("No data extracted from row: \(anObjectRow) -> \(objectColumns)")
}
}
}else{
CSVScanner.debug("Unable to load csv file from path: \(strBundle)")
if let errorString = encodingError?.description {
CSVScanner.debug("Received encoding error: \(errorString)")
}
}
}else{
CSVScanner.debug("Unable to get path to csv file: \(theFileName).csv")
}
}
}
Thanks in advance
If you are using Xcode 7+, you are also using Swift 2. Instead of passing an error pointer to the method, you need to use try.
The method signature has changed to convenience init(contentsOfFile path: String,
encoding enc: UInt) throws.
(Note: no error:.)

Difference between Printable and DebugPrintable in Swift

Looking for a Swift equivalent of Cocoa's description, I found the following protocols in Swift: Printable and DebugPrintable.
What's the difference between these two protocols and when should I use each one?
Here is an example class
class Foo: Printable, DebugPrintable {
var description: String {
return "Foo"
}
var debugDescription: String {
return "debug Foo"
}
}
This is how to use it.
println(Foo())
debugPrintln(Foo())
Here is the output with no surprises:
Foo
debug Foo
I didn't try this in a Playground. It works in an actual project.
The answer above was for Swift 1. It was correct at the time.
Update for Swift 2.
println and debugPrintln are gone and the protocols have been renamed.
class Foo: CustomStringConvertible, CustomDebugStringConvertible {
var description: String {
return "Foo"
}
var debugDescription: String {
return "debug Foo"
}
}
print(Foo())
debugPrint(Foo())
In Xcode 6 Beta (Version 6.2 (6C101)) I find that both println and debugPrintln use description if-and-only-if the class descends from NSObject. I don't see that either uses debugDescription at all but when run in a Playground debugPrintln outputs only to the Console and doesn't appear in the playground itself.
import Foundation
class Tdesc: NSObject, Printable, DebugPrintable {
override var description: String {return "A description"}
override var debugDescription: String {return "A debugDescription"}
}
class Xdesc: Printable, DebugPrintable {
var description: String {return "A description"}
var debugDescription: String {return "A debugDescription"}
}
let t = Tdesc()
let x = Xdesc()
t.description
let z: String = "x\(t)"
println(t) // Displays "A description" in the Playground and Console
debugPrintln(t) // Displays nothing in the Playground but "A description" in the Console
x.description
let y: String = "x\(x)"
println(x) // Displays "__lldb_expr_405.Xdesc" in the Playground and Console
debugPrintln(x)
I believe the main difference is the property that's used to print. Printable has description and DebugPrintable has debugDescription:
https://stackoverflow.com/a/24254220/887210
https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Printable.html#//apple_ref/doc/uid/TP40014608-CH11-SW1
Edit:
Apparently print() and println() don't work properly with Printable and DebugPrintable:
struct TestPrintable : Printable {
var description: String { return "Testing Printable" }
}
struct TestDebugPrintable : DebugPrintable {
var debugDescription: String { return "Testing DebugPrintable" }
}
println(TestPrintable()) // -> "__lldb_expr_42.TestPrintable"
println(TestDebugPrintable()) // -> "__lldb_expr_42.TestDebugPrintable"
More information about this:
http://vperi.com/2014/06/04/textual-representation-for-classes-in-swift/

Resources