Swift中的扩展功能,扩展静态功能和扩展类功能有什么区别?

Ale*_*ant 2 swift swift-extensions

我试图在UIColor上创建一个扩展函数,该函数可以采用Card.Colour类型的参数并将UIColor返回给调用方。

button.backgroundColor = UIColor.getColour(cardColour: cardToDeal.colour)


extension UIColor {
    func getColour(cardColour: Card.Colour) -> UIColor {
        switch cardColour {
        case .Red:
            return UIColor.red
        case .Green:
            return UIColor.green
        case .Blue:
            return UIColor.blue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试执行此操作时,UIColor.getColour的扩展功能要求我在扩展方法中输入UIColor类型的参数,而不是Card.Colour的指定类型。

但是,当我将getColour的扩展功能更改为:

static func getColour(cardColour: Card.Colour) -> UIColor {
class func getColour(cardColour: Card.Colour) -> UIColor {
Run Code Online (Sandbox Code Playgroud)

它允许我传递Card.Colour类型的参数

为什么是这样?为什么将函数更改为静态函数或类函数会更改需要传入的类型?

提前致谢!

(详细的答案将不胜感激)

has*_*emi 6

记住那UIColor是一堂课。类有点像用于创建符合该类的实例或对象的蓝图。UIColor.redUIColor该类实例的示例。

当您func在类内部定义一个内部(以您的情况作为扩展)时,Swift假定您要将其添加func到蓝图中,而该蓝图又将在UIColor该类的所有实例中可用UIColor.red

您也可以func将其放置在模块的顶层,而不是放置在所有类的外部,以将其定义在所有类之外extension

但是,为了使您的函数井井有条,您可以将类似的函数放在类名中。您只需要告诉Swift,您并没有在尝试将函数添加到将应用于所有实例的蓝图中,而是想要拥有一个名称以类名作为前缀的函数。

这是一个说明用法差异的示例:

class Test {
    func notStatic() {
        print("called from an instance")
    }

    static func thisIsStatic() {
        print("called on class name directly")
    }
}

let instance = Test() // this is an *instance* of Test

instance.notStatic() // we can call a non static func on instance

Test.thisIsStatic() // we can call a static func directly on the class only
Run Code Online (Sandbox Code Playgroud)

现在,让我们再回到您的特定示例。请注意,在您的示例中,您从的实例开始,Card.Colour并尝试创建的实例UIColor

换句话说,将a添加funcUIColor 实例(即non- staticclass)对您没有用,因为您还没有实例UIColor

创建类的新实例的惯用方式是使用初始化程序(init)。因此,您可以将函数变成UIColor上的初始化程序,如下所示:

extension UIColor {
    convenience init(cardColour: Card.Colour) {
        switch cardColour {
        case .Red: self.init(cgColor: UIColor.red.cgColor)
        case .Blue: self.init(cgColor: UIColor.blue.cgColor)
        case .Green: self.init(cgColor: UIColor.green.cgColor)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您只需致电UIColor(cardColour: .Red)即可获得想要的东西。需要注意的是在执行,我将UIColor.redcgColor和后面作为一个快速黑客攻击。可以UIColor针对每种情况随意使用您认为合适的初始化程序Card.Colour

但是还有另一种方式,我认为这更优雅。既然你已经有一个实例Card.Colour,可以延长Card.Colour使用,让您的一个功能UIColor对应的实例。在该函数中,您可以Card.Colour使用关键字引用实例self

由于您已经Card.Colour通过拥有实例self,因此您无需将任何参数传递给该函数。这使您可以使用一个很酷的功能,称为计算属性,以使用法更加美观。

这就是您将这样的扩展名添加到的方式Card.Colour

extension Card.Colour {
    var uiColor: UIColor {
        switch self {
        case .Red: return .red
        case .Blue: return .blue
        case .Green: return .green
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以得到一个UIColorCard.Colour这样Card.Colour.Red.uiColormainColour.uiColor,其中mainColour是类型Card.Colour

最后,正如Leo Dabus在评论中指出的那样,Swift的命名约定是大小写应以小写字母开头。您应该使用Card.Colour.red而不是Card.Colour.Red,等等。这些约定在Swift 3左右出现了。在此之前,通常将案例名称大写。