ios 将swift扩展标记为public是否会将扩展中的属性更改为隐式public或internal?

jogvjijk  于 2023-04-08  发布在  iOS
关注(0)|答案(1)|浏览(157)

在Apple文档中:

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

给出UIView扩展的子类:

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

这会将helloWorld标记为内部的,我没有问题,而且我在基于Objective-C的项目中看不到它。
但是,如果我将扩展标记为public:

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

现在helloWorld出现在我基于Objective-C的代码中,这意味着它被标记为public。
但是,我没有看到苹果提到这一点,是吗?
我刚刚看到文档说一个公共类仍然会有隐式的内部级别。

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的bug?我用的是swift 2.1和Xcode 7.2

gijlo24d

gijlo24d1#

**答案:**是的,在扩展前面放置访问级别修饰符(在您的情况下,具体为public),修改 * 该扩展范围内所有新类型的默认访问级别 *。

注意修饰符并不影响被扩展的类/结构/etc的访问级别(只影响其成员)。然而,有一些事情应该考虑,正如我将在下面讨论的那样。
在这次讨论中,我将发布一些关于Swift中访问级别的重要事实。所有这些都来自Swift Language Guide - Access Control - Access Levels
让我们先确认一下你已经说过的话:
如果您自己没有指定显式访问级别,则代码中的所有实体(如本章后面所述,有几个特定的例外)都具有默认访问级别internal
好的,这与你在问题中引用的内容一致:任何 new 类型成员,无论是在类还是结构定义中,都将具有 default 访问级别internal。
现在,让我们看看您可以在扩展前面添加的访问级别修饰符
可以在类、结构或枚举可用的任何访问上下文中扩展该类、结构或枚举。在扩展中添加的任何类型成员都具有与要扩展的原始类型中声明的类型成员相同的默认访问级别。* 如果扩展公共或内部类型,您添加的任何新类型成员都将具有默认访问级别internal。如果扩展private类型,则您添加的任何新类型成员都将具有默认访问级别private。*
或者,可以使用显式访问级别修饰符标记扩展(例如,私有扩展),以便为扩展中定义的所有成员设置新的默认访问级别。在扩展中,仍可为单个类型成员覆盖此新的默认值。
我们看一下你的例子,并假设你的类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"
        }
    }
}

考虑到上面的讨论,public extension ...中的helloWorld应该被标记为internal,因为在此上下文中,这是默认的访问级别。在扩展的上下文中,访问级别修饰符的工作方式与应用于类型时不同。
最后,我们应该指出,在扩展非公有类时使用public访问修饰符将在Swift中产生编译时错误。所以在上面的例子中:

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

我要说的是,上面描述的错误并不是为了避免运行时错误,而是为了避免冗余(和混乱)的代码:public成员类型或privateinternal类永远不会使用其public访问级别。

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. */

因此,只有在扩展上使用访问级别修饰符来 * 使默认访问级别更具限制性 * 才有意义,即使用public类的internal extension ...,或private extensioninternal类。

相关问题