使用 NSLog 记录 Swift 枚举

Posted

技术标签:

【中文标题】使用 NSLog 记录 Swift 枚举【英文标题】:Logging a Swift enum using NSLog 【发布时间】:2014-06-05 13:36:50 【问题描述】:

我正在尝试记录一个枚举:

enum CKAccountStatus : Int 
    case CouldNotDetermine
    case Available
    case Restricted
    case NoAccount


NSLog("%i", CKAccountStatus.Available)

编译器抱怨:

Type 'CKAccountStatus' does not conform to protocol 'CVarArg'

为什么?我试图转换值:

NSLog("%i", CKAccountStatus.Available as Int)

但这也不行:

Cannot convert the expression's type '()' to type 'String'

【问题讨论】:

你试过println吗? 我做了,它打印出(Enum Value)。正确,但不是很有帮助:) 【参考方案1】:

获取枚举的底层Int值:CKAccountStatus.Available.rawValue

枚举在 Swift 中并不是严格的整数,但如果它们是用底层类型声明的,你可以用 rawValue 来获得它——不管底层类型是什么。 (enum Foo: String 将为您提供 rawValue 等的字符串。)如果枚举没有基础类型,rawValue 将无能为力。在从 ObjC 导入的 API 中,使用 NS_ENUM 定义的任何枚举都具有底层整数类型(通常为 Int)。

如果您想打印更具描述性的枚举,您可以考虑对采用Printable 协议的枚举类型进行扩展。

【讨论】:

我发现对于简单的Int 枚举,.hashValue 还可以让您访问Int 值。 使用 hashValue 会滥用 API 合约。 Hashable 类型要求 hashValue 对于“相等”值是相同的,否则是唯一的,但不做其他保证......即使它巧合地返回与 rawValue 相同的 Int 枚举类型,你不要不知道将来不会改变。最好选择记录在案的 API 来做你想做的事,而不是碰巧做你想做的事。【参考方案2】:

枚举实际上是不透明的。它可能有原始值,你可以得到;但许多枚举没有。 (您不必将枚举声明为具有类型,如果不声明,则没有原始值。)我要做的是给枚举一个 description 方法并显式调用它。

区分枚举当前值的唯一方法是通过 switch 语句,因此您的description 方法将处理每种情况,并且 switch 语句的每种情况都会返回不同的描述性值。

enum Suit 
    case Hearts, Diamonds, Spades, Clubs
    func description () -> String 
        switch self 
        case Hearts:
            return "hearts"
        case Diamonds:
            return "diamonds"
        case Spades:
            return "spades"
        case Clubs:
            return "clubs"
        
    


var suit = Suit.Diamonds
println("suit \(suit.description())")  // suit diamonds

【讨论】:

【参考方案3】:

这是我的方法:

enum UserMode : String

   case Hold = "Hold";
   case Selecting = "Selecting";
   case Dragging = "Dragging";

然后,每当我需要打印原始值时:

//Assuming I have this declared and set somewhere
var currentMode: UserMode = .Selecting;

在做

NSLog("CurrentMode \(_currMode.rawValue)");

将打印:

当前模式选择

【讨论】:

【参考方案4】:

来自 Swift 文档:

如果您熟悉 C,您就会知道 C 枚举将相关名称分配给一组整数值。 Swift 中的枚举更加灵活,并且不必为枚举的每个成员提供值。如果为每个枚举成员提供了一个值(称为“原始”值),则该值可以是字符串、字符或任何整数或浮点类型的值。

因此,您不能尝试将其强制转换为和 Int。至于您的第一个问题,NSLog() 似乎正在寻找 C 变量类型的参数,这不适用于 Swift 枚举。

【讨论】:

【参考方案5】:

我明白了,在 Swift 中枚举不是数字:

与 C 和 Objective-C 不同,Swift 枚举成员没有分配一个 创建时的默认整数值。在指南针点 上面的例子,North、South、East 和 West 不隐式等于 0, 1、2和3。相反,不同的枚举成员是 完全成熟的价值观,具有明确定义的 CompassPoint 的类型。

那么有没有办法轻松记录该值?啊,有:

NSLog("%i", CKAccountStatus.Available.toRaw())

【讨论】:

【参考方案6】:

您可以使用toRaw() 函数获取枚举的 Int-Value,如下所示:

import Foundation

enum CKAccountStatus : Int 
    case CouldNotDetermine
    case Available
    case Restricted
    case NoAccount


let block = (status: Int) -> Void in
    NSLog("%d", status)


let status = CKAccountStatus.Available.toRaw()
block(status) // prints "1"

【讨论】:

如何打印“可用”?【参考方案7】:

对于我的错误枚举,我使用

public var localizedDescription : String  return String(reflecting: self) 

对于其他枚举,可以使用 CustomStringConvertible 协议

public var description : String  return String(reflecting: self) 

【讨论】:

以上是关于使用 NSLog 记录 Swift 枚举的主要内容,如果未能解决你的问题,请参考以下文章

是否有NSLog的Swift替代方案(@“%s”,__ PRETTY_FUNCTION__)

Swift:摆脱时间戳 NSLog()

Apple 推荐的 Swift 日志记录方法

NSLog(@"%s", __PRETTY_FUNCTION__) 是不是有 Swift 替代方案

如何在 Objective-C 中使用 Swift 字符串枚举?

如何动态构建 NSLog 的参数?