公共结构在框架初始化中因编译器中的“内部”保护级别而无法访问。

52

我在一个名为"MyFramework"的框架中有一个结构体。

public struct ShipmentPackage:Encodable {
  let package_code:String
  let weight:Float
}

然后当我尝试在另一个项目/框架中创建ShipmentPackage时

import MyFramework
let onePackage = ShipmentPackage(package_code:"BX",weight:100)

我收到一个错误信息:“ShipmentPackage”初始化程序不可访问,因为保护级别为“internal” 我进入了这个链接https://forums.swift.org/t/public-struct-init-is-unexpectedly-internal/5028

我试图将我的代码更改为以下内容:

第一次尝试:

public struct ShipmentPackage:Encodable {
  let package_code:String
  let weight:Float
  public init(package_code:String,weight:Float){
    self.package_code = package_code
    self.weight = weight
  }
}

第二次尝试:

public struct ShipmentPackage:Encodable {
  public let package_code:String
  public let weight:Float
  public init(package_code:String,weight:Float){
    self.package_code = package_code
    self.weight = weight
  }
}

我还尝试将package_code和weight更改为public,但以上方法都无效,编译时出现错误消息

<unknown>:0: error: 'init' is inaccessible due to 'internal' protection level
<unknown>:0: note: 'init' declared here
<unknown>:0: error: 'init' is inaccessible due to 'internal' protection level

任何提示都将不胜感激!


1
展示一下你是如何调用你所编写的初始化器的。 - mag_zbc
我也看到了这个链接:http://taylorfranklin.me/2016/07/10/the-default-memberwise-initializers-headache/,它和我的情况非常相似,但是对我来说并没有起作用,因为它在编译时显示错误。我需要进行编译设置吗? - Qiquan Lu
无法复现。我已将您的“第一次尝试”复制到一个框架中,并且可以从主应用程序中无问题地调用初始化程序。 - Martin R
1
@MartinR 谢谢,我找到问题了,它不是由这个结构体引起的,而是使用这个结构体的另一个结构体没有公共初始化程序。 - Qiquan Lu
3个回答

77
经验教训: 所有公共结构体需要一个公共初始化函数。
这并不完全准确。 文档 表明:

结构体类型的默认成员逐一初始化器

如果结构体的任何存储属性是私有的,则该结构体类型的默认成员逐一初始化器被视为私有的。同样,如果结构体的任何存储属性是文件私有的,则初始化器是文件私有的。否则,初始化器具有内部的访问级别。
因此,内置的成员逐一初始化器仅在包内可用。如果您不提供公共初始化函数,则无法从外部创建结构体。
public struct YourFrameworkStruct {
    let frameworkStructProperty: String!
    /// Your public structs in your framework need a public init.
    /// 
    /// Don't forget to add your let properties initial values too.
    public init(frameworkStructProperty: String) {
        self.frameworkStructProperty = frameworkStructProperty
    }
}

49
这对于有数十个带有默认值结构体的图书馆来说确实是一个很大的缺点。 - elect
7
「来自外太空」为我带来了笑容 :)。 - Duncan Babbage
1
它应该与结构体属性的最低访问级别相同。 - Míng

6

感谢所有的评论,我终于弄清楚为什么它会给我报错了。我的两次尝试都应该没问题。

结果证明这个结构体并没有引起问题。

我有其他的结构体使用了这个结构体,并标记为public,例如

public struct Shipment:Encodable {
  let carrier_code:String
  let packages:[ShipmentPackage]
}

缺少初始化器,但由于某种原因,XCode不会在我的工作区指示错误,但会在编译时给出错误。

在为所有公共结构提供初始化器后,应用程序通过了编译器。

public struct Shipment:Encodable {
  let carrier_code:String
  let packages:[ShipmentPackage]
  public init(carrier_code:String,packages:[ShipmentPackage]){
      self.carrier_code = carrier_code
      self.packages = packages
  }
}

我的原始帖子并不是特别好,因为我发布的代码没有问题,但是我决定不删除这个帖子,因为它可能有助于像我这样的新手在未来学习。

教训:所有公共结构都需要公共初始化。


1

当你试图访问不同框架中的结构体时, **

结构体内的所有变量都应该是公共的,并且在初始化中应设置默认值。

**

例:

公共结构体LocationPoint { 公共变量位置: NSNumber 公共变量颜色: UIColor

    public init(location: NSNumber? = 0, color: UIColor? = nil ) {
        self.location = location ?? 0
        self.color = color ?? UIColor.init(red: 255.0/255.0, green: 1.0, blue: 205/255.0, alpha: 1)
    }
}

您也可以根据调用结构体的方式,将初始化写成以下形式。
 public init() {
     self.location = 0
     self.color = UIColor.init(red: 255.0/255.0, green: 1.0, blue: 205/255.0, alpha: 1)
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接