【问题标题】:How can you mimic the description output?你如何模仿描述输出?
【发布时间】:2015-12-24 04:39:29
【问题描述】:

想象一个水果类:

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>

问题:你如何模仿这个输出?

我目前有以下:

class Fruit: NSObject {
    override var description:String {
        print(super.description)
        return "<\(NSStringFromClass(self.dynamicType)): 0x\(String(self.hash, radix:16))>"
    }
}

现在输出以下内容:

<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c22df0>
<MyProject.Fruit: 0x7fb958c22df0>

如您所见,输出与我想要的相同。现在我想知道这是否是模仿其输出的正确方法,或者我忽略了下面 cmets 中提到的某些内容。

致谢:Matt、Martin R 和 Vacawama

【问题讨论】:

  • 你的类是如何定义的?如果你不覆盖它,self.description 会打印什么?
  • “这给了我完全相同的输出 print(super.description) 会做”不,它没有,因为哈希不是内存地址。这似乎是一个没有提出你真正想要答案的问题的情况......
  • 对不起让我改写问题。
  • 我重写了这个问题,这样更好吗?
  • @Mark:如果你不覆盖描述方法,那么你会得到相同的输出,因为描述方法是从 NSObject 继承的。

标签: swift class dynamictype


【解决方案1】:

NSObject 的任何子类都继承 NSObjectdescription方法(在NSObjectProtocol中定义):

class Foo1 : NSObject { }
print(Foo1())
// <MyProject.Foo1: 0x100612fd0>

这个“默认实现”打印类名和内存 对象的地址,例如 Friday Q&A 2013-01-25: Let's Build NSObject,这里展示了 Objective-C 的实现方式 可能看起来像:

- (NSString *)description
{
    return [NSString stringWithFormat: @"<%@: %p>", [self class], self];
}

%p 格式将指针的值打印为十六进制数, 前面是0x

为了在 Swift 中模仿这一点,我们可以使用

  • String(reflecting: self.dynamicType) 将完全限定的类名作为字符串返回,并且
  • unsafeAddressOf(self) 返回指向存储的指针 对象。

示例(使用方括号 [] 来证明 使用覆盖的方法):

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]

这也适用于“纯 Swift 类”,因为没有 Foundation 使用方法:

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]

注意(如上面 cmets 中已经提到的),哈希值 对象的地址不一定与内存地址相同。 一个简单的例子是NSArray(),它的哈希值就是数字 元素:

let array = NSArray(objects: 1, 2, 3)
print(unsafeAddressOf(array)) // 0x00000001020011a0
print(array.hashValue) // 3

Swift 3 更新:

class Bar : CustomStringConvertible {
    var description : String {
        let className = String(reflecting: type(of: self))
        let address = Unmanaged.passUnretained(self).toOpaque()
        return "[\(className): \(address)]"
    }
}

【讨论】:

  • 惊人的回答 Martin R,感谢您的时间和努力。
【解决方案2】:

使用String(self.hash, radix:16)。您可能需要自己为 0x 添加前缀。

【讨论】:

  • 或者:String(format: "%#x", hash),'#' 格式标志会导致 '0x' 被添加 :)
  • 你们都是英雄...无法将其标记为答案(9 分钟和计数)
  • 但是,我猜这是一个误解。哈希不是内存地址。
  • @vacawama:你是对的,这取决于你是在 32 位还是 64 位平台上。 String(format: "%#zx", hash) 在任何一种情况下都可以工作,因为意外地Intsize_t 具有相同的大小。马特的建议可能是最好的。
  • 另外,如果你要在这个对象上实现 Equatable,你还需要以不同的方式实现 hash,这样哈希就真的不再是内存地址了(因为两个不同的实例可能具有相同的哈希)。
猜你喜欢
  • 2011-03-09
  • 2021-12-05
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 2019-10-02
相关资源
最近更新 更多