标记快速扩展公共标识会将扩展中的属性更改为隐式公开还是内部?

时间:2015-12-26 10:45:10

标签: ios swift

所以在Apple文档中:

扩展中添加的任何类型成员都具有与要扩展的原始类型中声明的类型成员相同的默认访问级别。如果您扩展公共或内部类型,则您添加的任何新类型成员的默认访问权限级别为内部

给出UIView扩展的子类:

extension UIViewSubClass
{
    var helloWorld : String {
        get {
            return "helloWorld"
        }
    }
}

这会将helloWorld标记为内部,我没有问题,我在基于Objective-C的项目中看不到它。

但是,如果我将扩展标记为公开:

public extension UIViewSubClass
{
    var helloWorld : String {
        get {
            return "helloWorld"
        }
    }
}

现在helloWorld在我的基于Objective-C的代码中出现,这意味着它被标记为公开。

但是,我没有看到Apple提到这一点,是吗?

我刚看到文档说公共类仍然具有隐含的内部级别。

public class SomePublicClass {          // explicitly public class
    public var somePublicProperty = 0    // explicitly public class member
    var someInternalProperty = 0         // implicitly internal class member
    private func somePrivateMethod() {}  // explicitly private class member
}

标记公共扩展似乎与标记类定义有不同的效果。这让我很困惑。

有人可以帮助我,这应该是这样,还是这是一种快速的错误?我使用swift 2.1和Xcode 7.2

1 个答案:

答案 0 :(得分:12)

答案:是的,在扩展程序前放置访问级别修饰符(在您的情况下,public)会修改范围内所有新类型的默认访问级别该扩展名

请注意,修饰符不会影响正在扩展的类/ struct / etc的访问级别(只有它的成员。但是,有些事情应该被考虑,我将在下面讨论。

在本次讨论中,我将发布一些关于Swift访问级别的重要事实。所有这些都来自Swift Language Guide - Access Control - Access Levels

让我们首先确定您已经说过的内容:

  

代码中的所有实体(有一些特定的例外情况,如   在本章后面描述)具有默认访问级别   如果您没有自己指定显式访问级别,则内部

好的,这符合您在问题中引用的内容:任何类型成员,无论是在类或结构定义中,都将具有默认内部访问级别。

现在,让我们看看您可以在扩展程序前添加的访问级别修饰符

  

您可以在任何访问中扩展类,结构或枚举   类,结构或枚举可用的上下文。   在扩展中添加的任何类型成员都具有相同的默认访问权限   level作为在扩展的原始类型中声明的类型成员。 如果   您扩展公共或内部类型,您添加的任何新类型成员   将具有内部的默认访问级别。如果你扩展私人   类型,您添加的任何新类型成员将具有默认访问级别   私人即可。

     

或者,您可以使用显式访问级别标记扩展名   修饰符(例如,私有扩展名),用于设置新的默认访问权限   扩展程序中定义的所有成员的级别。这个新的默认值   仍然可以在个人类型的扩展名中覆盖   成员。

这样可以解决问题。我们查看您的示例,并假设您的类UIViewSubClass具有访问级别public(或编译时错误,如下所示):

/* no access level modifier: default access level will be 'internal' */
extension UIViewSubClass
{
    // default access level used: internal
    var helloWorld : String { 
        get {
            return "helloWorld"
        }
    }
}

// modify default access level to public
public extension UIViewSubClass
{
    // default access level used: public
    var helloWorld : String { 
        get {
            return "helloWorld"
        }
    }
}

考虑到上述问题,我们希望您helloWorld中的public extension ...被标记为internal,因为在此上下文中,这是默认访问级别。在扩展的上下文中,访问级别修饰符的工作方式与应用于类型时的工作方式不同。

最后,我们应该指出在扩展非公共类时使用public访问修饰符将在Swift中产生编译时错误。所以在你的情况下:

  • 如果UISubViewClassinternalprivate类,则该类上的public extension ...将产生编译时错误。
  • 如果UISubViewClasspublic类,那么添加public extension将是多余的,因为根据定义,公共类的默认访问修饰符已经是public

我要说上面描述的错误实际上不是一个错误,以避免运行时错误,而是避免冗余(和混乱)代码:public成员类型或private或{{1类永远不会使用它internal public`访问级别。

s

因此,在的扩展上使用访问级别修饰符才能使默认访问级别更具限制性,即使用class MyImplicitlyInternalClass { private var myExplicitlyPrivateVar = 0 var myImplicitlyInternalVar = 0 public var myExplicitlyPublicVar = 0 // warning, see (Note 1) below // redundant 'public': can never be accessed publicly // myExplicitlyPublicVar will behave as 'internal' } public extension MyImplicitlyInternalClass { // error, see (Note 2) var myNewVarIsInternal : Int { get { return 0 } } } /* (Note 1) Compile type warning: "Declaring a public var for an internal class." (Note 2) Compile time error: "Extension of internal class cannot be declared public." Summary: in theory, these two above are the same type of 'faults', but only the latter is flagged as and error. */ 类的internal extension ... ,或publicprivate extension类。