Imagine a class Fruit:
class Fruit: NSObject {
override var description:String {
return super.description
}
}
var apple = Fruit()
var banana = Fruit()
print(apple) // Output: <MyProject.Fruit: 0x7fa719627e00>
print(banana) // Output: <MyProject.Fruit: 0x7fa71962dab0>
Question: How can you mimic this ouput?
I currently have the following:
class Fruit: NSObject {
override var description:String {
print(super.description)
return "<\(NSStringFromClass(self.dynamicType)): 0x\(String(self.hash, radix:16))>"
}
}
Which now outputs the following:
<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c22df0>
<MyProject.Fruit: 0x7fb958c22df0>
As you can see the output is the same which is what I wanted. Now I am wondering if this is the proper way to mimic it's output or that I am overlooking something as mentioned in the comments below.
Credits: Matt, Martin R and Vacawama
Any subclass of NSObject inherits the
description method of NSObject (which is defined in the NSObjectProtocol):
class Foo1 : NSObject { }
print(Foo1())
// <MyProject.Foo1: 0x100612fd0>
This "default implementation" prints the class name and the memory
address of the object, see for example
Friday Q&A 2013-01-25: Let's Build NSObject, where it is shown how the Objective-C implementation
could look like:
- (NSString *)description
{
return [NSString stringWithFormat: #"<%#: %p>", [self class], self];
}
The %p format prints the value of a pointer as a hexadecimal number,
preceded by 0x.
To mimic that in Swift, we can use
String(reflecting: self.dynamicType) which returns the fully-qualified class name as a string, and
unsafeAddressOf(self) which returns a pointer to the storage
of the object.
Example (using square brackets [] to demonstrate that the
overridden method is used):
class Foo2 : NSObject {
override var description : String {
let className = String(reflecting: self.dynamicType)
let address = unsafeAddressOf(self)
return String(format: "[%#: %p]", className, address)
}
}
print(Foo2())
// [MyProject.Foo2: 0x100613310]
class Foo3 : Foo2 { }
print(Foo3())
// [MyProject.Foo3: 0x102000540]
This works for "pure Swift classes" as well, because no Foundation
methods are used:
class Bar : CustomStringConvertible {
var description : String {
let className = String(reflecting: self.dynamicType)
let address = unsafeAddressOf(self)
return String(format: "[%#: %p]", className, address)
}
}
print(Bar())
// [MyProject.Bar: 0x102001200]
Note that (as already mentioned in above comments), the hash value
of an object is not necessarily identical to the memory address.
A simple example is NSArray() whose hash value is just the number
of elements:
let array = NSArray(objects: 1, 2, 3)
print(unsafeAddressOf(array)) // 0x00000001020011a0
print(array.hashValue) // 3
Update for Swift 3:
class Bar : CustomStringConvertible {
var description : String {
let className = String(reflecting: type(of: self))
let address = Unmanaged.passUnretained(self).toOpaque()
return "[\(className): \(address)]"
}
}
Use String(self.hash, radix:16). You might need to prefix the 0x yourself.
Related
I am a beginner Swift learner and I have a question about protocols. I have followed a tutorial that teaches you about linked lists, which is as follows:
Node:
class LinkedListNode<Key> {
let key: Key
var next: LinkedListNode?
weak var previous: LinkedListNode?
init (key: Key) {
self.key = key
}
}
And the linked list:
class LinkedList<Element>: CustomStringConvertible {
typealias Node = LinkedListNode<Element>
private var head: Node?
// irrelevant code removed here
var description: String {
var output = "["
var node = head
while node != nil {
output += "\(node!.key)"
node = node!.next
if node != nil { output += ", " }
}
return output + "]"
}
}
The var description: String implementation simply lets you to print each elements in the linked list.
So far, I understand the structure of the linked list, my problem isn't about the linked list actually. What I don't understand is the protocol CustomStringConvertible. Why would it be wrong if I have only the var description: String implementation without conforming to the protocol? I mean, this protocol just simply say "Hey, you need to implement var description: String because you are conformed to me, but why can't we just implement var description: String without conforming to the protocol?
Is it because in the background, there is a function or some sort that takes in a type CustomStringConvertible and run it through some code and voila! text appears.
Why can't we just implement var description: String without conforming to the protocol?
Compare:
class Foo {
var description: String { return "my awesome description" }
}
let foo = Foo()
print("\(foo)") // return "stackoverflow.Foo" (myBundleName.Foo)
and
class Foo: CustomStringConvertible {
var description: String { return "my awesome description" }
}
let foo = Foo()
print("\(foo)") // return "my awesome description"
When you use CustomStringConvertible, you warrant that this class have the variable description, then, you can call it, without knowing the others details of implementation.
Another example:
(someObject as? CustomStringConvertible).description
I don't know the type of someObject, but, if it subscriber the CustomStringConvertible, then, I can call description.
You must conform to CustomStringConvertible if you want string interpolation to use your description property.
You use string interpolation in Swift like this:
"Here's my linked list: \(linkedList)"
The compiler basically turns that into this:
String(stringInterpolation:
String(stringInterpolationSegment: "Here's my linked list: "),
String(stringInterpolationSegment: linkedList),
String(stringInterpolationSegment: ""))
There's a generic version of String(stringInterpolationSegment:) defined like this:
public init<T>(stringInterpolationSegment expr: T) {
self = String(describing: expr)
}
String(describing: ) is defined like this:
public init<Subject>(describing instance: Subject) {
self.init()
_print_unlocked(instance, &self)
}
_print_unlocked is defined like this:
internal func _print_unlocked<T, TargetStream : TextOutputStream>(
_ value: T, _ target: inout TargetStream
) {
// Optional has no representation suitable for display; therefore,
// values of optional type should be printed as a debug
// string. Check for Optional first, before checking protocol
// conformance below, because an Optional value is convertible to a
// protocol if its wrapped type conforms to that protocol.
if _isOptional(type(of: value)) {
let debugPrintable = value as! CustomDebugStringConvertible
debugPrintable.debugDescription.write(to: &target)
return
}
if case let streamableObject as TextOutputStreamable = value {
streamableObject.write(to: &target)
return
}
if case let printableObject as CustomStringConvertible = value {
printableObject.description.write(to: &target)
return
}
if case let debugPrintableObject as CustomDebugStringConvertible = value {
debugPrintableObject.debugDescription.write(to: &target)
return
}
let mirror = Mirror(reflecting: value)
_adHocPrint_unlocked(value, mirror, &target, isDebugPrint: false)
}
Notice that _print_unlocked only calls the object's description method if the object conforms to CustomStringConvertible.
If your object doesn't conform to CustomStringConvertible or one of the other protocols used in _print_unlocked, then _print_unlocked creates a Mirror for your object, which ends up just printing the object's type (e.g. MyProject.LinkedList) and nothing else.
CustomStringConvertible allows you to do a print(linkedListInstance) that will print to the console whatever is returned by the description setter.
You can find more information about this protocol here: https://developer.apple.com/reference/swift/customstringconvertible
Is there anyway to use conversion using a variable? I am using object stacking using type of "AnyObject" and I've been able to take the class type and populate a variable. Now I need to populate an array using conversion.
var myString = "Hello World"
var objectStack = [AnyObject]()
objectStack.append(myString)
let currentObject = String(describing: objectStack.last!)
var objectType = String()
let range: Range<String.Index> = currentObject.range(of: ":")!
objectType = currentObject.substring(to: range.lowerBound)
let range2: Range<String.Index> = objectType.range(of: ".")!
objectType = objectType.substring(from: range2.upperBound)
The code above will evaluate the class and set the value of "objectType" to "String". Now I'm trying to go the other way. Something like this:
for obj in objectStack{
obj = newObject as! objectType //this doesn't work
}
Is something like this possible?
There is a simpler, safer way to get the type:
let type = type(of: objectStack.last!) // String.Type
let typeString = String(describing: type) // "String"
The other way around is not possible because the type of the object is not known at compile time. Do you have a number of known types you want to try to cast to? In that case, use optional binding to check if the cast is successful:
let object = objectStack.last!
if let string = object as? String {
// do String stuff
}
else if let i = object as? Int {
// do Int stuff
}
// and so on
If you have a large number of possible types that share some common functionality: Use Protocols. See Swift Documentation for a nice introduction.
You define a protocol for some common functionality that different types can implement:
protocol Stackable {
func doStuff()
// (more methods or properties if necessary)
}
The protocol provides a contract that all types conforming to this protocol have to fulfill by providing implementations for all declared methods and properties. Let's create a struct that conforms to Stackable:
struct Foo: Stackable {
func doStuff() {
print("Foo is doing stuff.")
}
}
You can also extend existing types to make them conform to a protocol. Let's make String Stackable:
extension String: Stackable {
func doStuff() {
print("'\(self)' is pretending to do stuff.")
}
}
Let's try it out:
let stack: [Stackable] = [Foo(), "Cat"]
for item in stack {
item.doStuff()
}
/*
prints the following:
Foo is doing stuff.
'Cat' is pretending to do stuff.
*/
This worked for me:
var instance: AnyObject! = nil
let classInst = NSClassFromString(objectType) as! NSObject.Type
instance = classInst.init()
I have been updating my game recently to use more value types. I am still not 100% confident with weak and unowned in some cases so I went the struct way to avoid strong reference cycles. As per apples newer keynotes it seems value types are they way to go for the most part anyway.
I have never seen an example where structs are used to render sprites in a spriteKit game so I wonder what the drawbacks are.
I understand that they are copied and not referenced but for my usage it seems to work.
So basically is there something I need to watch out for when doing this
struct Flag {
let post: SKSpriteNode
let flag: SKSpriteNode
init(postImage: String, flagImage: String) {
post = SKSpriteNode(imageNamed: postImage)
// other set ups for post sprite
flag = SKSpriteNode(imageNamed: flagImage)
// other set ups for flag sprite
post.addChild(flag)
}
func animate() {
// code to animate flag
}
}
Than in my SKScenes I simply add them as usual
let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
flag.post.position = ...
addChild(flag.post)
flag.animate()
Now even if I create multiple flags in the same scene I seem to have no problems with this way.
I am just curious because I have never really seen an example like this so I wonder if I am missing something, like performance drawbacks etc.
Thanks for any help.
Personally I avoid creating Structs that contain Classes. Because Structs copy, each and every copy that get's passed around your app will increase the reference count of the Classes. This makes it harder to manage them instead of easier.
It is also useful to take a look at how UIKit uses Structs. A UIView is an object but has many defining properties that are Structs. For example it's frame.
Drop the code below in a playground to see some effects of this behaviour.
The protocol is just to get some meaningful feedback form the playground.
protocol IDLookable : CustomPlaygroundQuickLookable {
var id : Int { get set }
}
extension IDLookable {
func customPlaygroundQuickLook() -> PlaygroundQuickLook {
return PlaygroundQuickLook.AttributedString(NSAttributedString(string: "\(self.dynamicType) with id : \(self.id)"))
}
}
class MyClass : IDLookable {
var id : Int = 0
init(id : Int) {
self.id = id
}
}
struct MyContainerStruct : IDLookable {
var id : Int = 0
var object : MyClass
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 2
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 3
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
// altering the object in one struct will obvously update all references
structContainerTwo.object.id = 1
structContainer.object // 1
structContainerTwo.object // 1
}
}
let test = Scope()
One pattern that does make it easy to work with Reference Types in Value Types is to store them as weak optionals in the Value Types. This means that something will need to have a strong reference but chances are that some Class will be responsible for creating the Structs this is a good place to keep that strong reference.
struct MyContainerStruct : IDLookable {
var id : Int = 0
weak var object : MyClass?
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 1
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 1
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
}
}
let test = Scope()
Hi i want to append string by reference to a List.
for example :
var str = "old"
func foo(){
list.append(str)
}
func changeStr(){
str = "new"
}
my problem is that the value of str ("old") is being appended and not the reference, so when i change str to "new" it doesn't take any effect on the list.
my question is how i can append reference to a string var?
thanks.
You have to wrap the string in a class. Have the array hold members of your class, and update the class object with a new string value.
Just like if you had an array of ints in whatever language you are used to.
Best solution is to get used to standard Swift/functional idioms.
-- EXAMPLE --
class StringObject {
init(str: String) {
self.str = str
}
var str: String = ""
}
let so = StringObject(str: "old")
func foo() {
list.append(so)
}
func changeStr() {
so.str = "new"
}
In the example below T refers to a type that extends NSManagedObject, so why can I not call.
I do not have access to an instance of the class
private func getNewManagedObject <T: NSManagedObject>(type: T.Type) -> T {
// Let's assume all Entity Names are the same as Class names
let className = "" /*Somehow get class name from type ("User")*/
return NSEntityDescription.insertNewObjectForEntityForName(className, inManagedObjectContext: managedObjectContext) as T
}
getNewManagedObject(User.self);
Swift classes can be given a custom Objective-C name, what will make NSStringFromClass print a nicer output in a playground.
import CoreData
#objc(User) class User : NSManagedObject {
}
let className = NSStringFromClass(User.self) // className will be "User"
Without it, NSStringFromClass will print 'ModulName.ClassName' which is arguably better than 'ClassName' only. The ugliness of the playground output is due to the fact that playgrounds have some cryptic implicit module names.
With some experimenting I found out the following. In Playground you can do
class User : NSManagedObject {
}
let s = NSStringFromClass(User) // cryptic output: "__lldb_expr_XX.User"
The XX is some random number. At this point you can get the entity name with
let entityName = s.pathExtension // "User"
It's a bit hacky but maybe it could work for you.
quickly in Swift:
let className = String(YourClass)
Extension variant (in my opinion, it's more convenient):
extension NSObject {
class var string: String{
get {
return String(self)
}
}
}
//using:
let className = YourClass.string
Switf 2 solutions
let className = String(Int.self) // String
let className2 = String(4.dynamicType) // Int
func doThings<T>(type: T.Type) -> String {
return String(T) // Whatever type passed
}