Difference between Printable and DebugPrintable in Swift - cocoa

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/

Related

"Argument labels '(options:)' do not match any available overloads" occurs in PagingMenuController

I use PagingMenuController 2.0.0 in my project using swift3.
I have a problem when I write following codes.
These codes are copied from README of PagingMenuController.
An error "Argument labels '(options:)' do not match any available overloads" occurs in the last line.
struct MenuItem1: MenuItemViewCustomizable {}
struct MenuItem2: MenuItemViewCustomizable {}
struct MenuOptions: MenuViewCustomizable {
var itemsOptions: [MenuItemViewCustomizable] {
return [MenuItem1(), MenuItem2()]
}
}
struct PagingMenuOptions: PagingMenuControllerCustomizable {
var componentType: ComponentType {
return .all(menuOptions: MenuOptions(), pagingControllers: [UIViewController(), UIViewController()])
}
}
let options = PagingMenuOptions()
let pagingMenuController = PagingMenuController(options: options)

Swift 2.0 beta: are protocols kinda broken in Xcode beta 5?

Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work

ARC of Swift protocol objects

ARC is deinitializing my protocol objects that still have active references, is this a bug or is it expected behavior, and what is the workaround?
protocol SomeProtocol: class {
...
}
class SomeClass: SomeProtocol {
...
}
class ClassA {
var protocolObject: SomeProtocol!
...
}
class ClassB {
var x: SomeClass!
func f() {
self.x = SomeClass()
var objA = ClassA()
objA.protocolObject = self.x
}
}
In this example, when objA is deinitialized, it attempts to deinitialize objA.protocolObject, even though there is still a reference active as objB.x. This causes a runtime error EXC_BAD_ACCESS. However, if ClassA is defined as follows:
class ClassA {
var protocolObject: SomeClass
}
The code runs without error and protocolObject is not deinitialized. Any thoughts?
Update
This bug seems to be resolved as of iOS8.0.
I'm experiencing the same problem, and have narrowed down to the issue to the protocol being defined as a Class-Only Protocol (i.e. protocol XXX: class).
protocol FooProtocol {
var name: String { get }
}
// Note: Class-Only protocol
protocol BarProtocol: class {
var name: String { get }
}
class Foo: FooProtocol {
let name: String = "Foo"
deinit {
println("\(name) deinit")
}
}
class Bar: BarProtocol {
let name: String = "Bar"
deinit {
println("\(name) deinit")
}
}
class Container {
let foo: FooProtocol = Foo()
let bar: BarProtocol = Bar()
}
class ViewController: UIViewController {
let container = Container()
override func viewDidLoad() {
super.viewDidLoad()
// Prints 'Test: Foo'
test(container.foo)
// Prints 'Test: Bar', followed by 'Bar deinit'
// subsequent access to the `bar` variable results in a crash
test(container.bar)
}
func test(bar: BarProtocol) {
println("Test: \(bar.name)")
}
func test(foo: FooProtocol) {
println("Test: \(foo.name)")
}
}
Current workaround is to either forgo using class-only protocol. I have filed a bug report to Apple, rdar://18287447.

Class variables not yet supported

I begin my project with a split view controller as initial view controller and start it automatically from storyboard.
Generally, an app with this UI have one and only one split view controller as root, so I create a static variable in the subclass and set it when initialisation was done.
So I want try this behaviour with swift.
I read the Swift programming language guide book on iBook about Type properties (with static and class keyword) and trying a piece of code to the job:
import UIKit
class SplitViewController: UISplitViewController {
class func sharedInstance() -> SplitViewController {
return SplitViewController.instance
}
class let instance: SplitViewController = nil
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.initialization()
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder);
self.initialization()
}
func initialization() {
SplitViewController.instance = self;
}
}
but I figured out when Xcode say the class keyword for type properties wasn't supported yet.
Did you have a solution to do this ?
Embedding a struct can work just fine as a workaround:
class SomeClass
{
// class var classVariable: Int = 0
// "Class variables not yet supported." Weird.
// Workaround:
private struct SubStruct { static var staticVariable: Int = 0 }
class var workaroundClassVariable: Int
{
get { return SubStruct.staticVariable }
set { SubStruct.staticVariable = newValue }
}
}
The SomeClass.workaroundClassVariable computed type property can then be used as if it were a stored type property.
Swift now has support for static variables in classes. This is not exactly the same as a class variable (because they aren't inherited by subclasses), but it gets you pretty close:
class X {
static let y: Int = 4
static var x: Int = 4
}
println(X.x)
println(X.y)
X.x = 5
println(X.x)
It seems to be possible to declare variables with static storage duration in file scope (as in C):
var sharedInstance: SplitViewController? = nil
class SplitViewController: UISplitViewController {
....
func initialization() {
sharedInstance = self
}
}
My preferred method is to just use a private file scope var outside of the class and then implement class/static getters and setters:
private var _classVar: Int = 0;
class SomeClass
{
public class var classVar: Int
{
get { return _classVar }
set { _classVar = newValue }
}
}
As of Swift 1.2 (available with Xcode 6.3b1 and onwards), static class properties and methods are supported.
class SomeClass
{
static var someVariable: Int = 0
}
Using a dispatch_once singleton model in Swift
Seems to be the best answer so far, avoiding the use of a global variable.
A solution enough similar than var in file scope but more customisable and near singleton is to use a struct which support static var as property of class
struct PersonSharedData {
static var backstore = ""
var data: String {
get { return PersonSharedData.backstore }
set { PersonSharedData.backstore = newValue }
}
}
class Person {
var shared=PersonSharedData() //<< pseudo class var
var family: String {
get { return shared.data }
set { shared.data=newValue }
}
var firstname = ""
var lastname = ""
var sexe: Sexe = .Unknown
}
Ok, with the solution of Nikolai that do the work. I post my changes in this thread for information
var instance: SplitViewController? = nil
class SplitViewController: UISplitViewController {
class func sharedInstance() -> SplitViewController? {
return instance;
}
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.initialization()
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder);
self.initialization()
}
func initialization() {
instance = self
}
}
and for example, in my appDelegate, I can access this static method like this
SplitViewController.sharedInstance()!.presentsWithGesture = false
The wording in the error heavily implies this will be a language feature in the future.
You may want to resort temporarily to declaring a property variable in the Application Delegate and retrieve it from there. Not ideal, definitely an anti-pattern, but would give you a central place to retrieve the UISplitViewController when needed.
You have to wrap the class variables inside an inner struct variable
class Store{
var name:String
var address:String
var lat:Int
var long:Int
init(name:String, address:String, lat:Int, long:Int){
self.name = name
self.address = address
self.lat = lat
self.long=long
}
private struct FACTORY_INITIALIZED_FLAG { static var initialized: Bool = false
static var myStoreList:[Store]?
static func getMyStoreList()->[Store]{
if !initialized{
println("INITIALIZING")
myStoreList = [
Store(name: "Walmart", address: "abcd", lat: 10, long: 20),
Store(name: "JCPenny", address: "kjfnv", lat: 23, long: 34)
]
initialized = true
}
return myStoreList!
}
}
}
var a = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()
var b = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()
// only prints INITIALIZING once
Try this:
class var instance: SplitViewController {
return nil
}
It is called Type Property in Swift.
You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation. The example below shows the syntax for stored and computed type properties:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
Read more at link below,
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID254

How can I output to STDERR with Swift?

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)

Resources