swift - Type extensions from a framework's dependency available in app
问题描述
OK... this is difficult to explain (and to come up with a title for) but I'll try my best.
We first discovered this when using Carthage to import stuff but setting up a sample project in Xcode (without using Carthage) it seems to have done the same thing.
First, here's a screenshot of the sample project we set up...
The have a target Test20000 and it has a dependency A.
The A framework then has a dependency on B.
Important
The Test20000 app does NOT add B as a direct dependency.
The frameworks
In B there is a struct like...
import Foundation
public struct BType {
public let value = "Hello, B!"
}
In A there is a file like...
import Foundation
import B
public struct AType {
public let value = "Hello, A!"
public func doAThing() {
print(BType().value)
}
}
The App
Now in the Test20000 app we do something like...
import Foundation
import A
struct TestType {
func doSomething() {
let aType = AType()
print(aType.value)
aType.doAThing()
}
}
This works as expected. It prints...
Hello, A! Hello, B!
If I change the function to something like this...
import Foundation
import A
struct TestType {
func doSomething() {
let bType = BType()
print(bType.value)
}
}
Then this doesn't compile as B is not imported and so BType
can't be accessed.
The catch!
However! If you declare an extension in B something like...
extension String {
func doAThingInB() {
print(self)
}
}
Then now... without any changes to the imports and the dependencies, I can now change my app code to...
import Foundation
import A
struct TestType {
func doSomething() {
"Hello, bug!".doAThingInB()
}
}
And this will print out as though the extension is public to the actual App. It sort of "bunny hops" from B, over A and into the app.
I feel like this shouldn't happen at all.
We can't find a way to turn this off or to stop this happening.
Is this a bug?
Is there something we need to do to stop this?
Thanks
解决方案
我曾尝试使用私有模块映射来隐藏内部框架,使其用户不可见A
,但没有运气。可能与[SR-2896] 私有模块映射无法正常工作有关。
我想这是现在的预期行为。swift.org 论坛上有多个提案可以实现您想要的东西,例如命名空间 x 子模块或更相关的一个@_exported 和修复导入可见性。
上一篇的相关部分:
今天的 Swift 设计得更像 Java、C# 或 Python,因为如果你在 Foo 的实现中导入 Bar,它不会影响导入 Foo 的客户端。或者,它不会让导入 Foo 的客户看到 Bar 的顶级名称。
您仍然需要 Bar,因为编译器不会跟踪您是否在 Foo 的公共接口中使用了它的一种类型。(这是上一节。)
Bar 中的扩展仍然对导入 Foo 的客户端可见,因为编译器不区分扩展来自今天的位置。
Bar 中的运算符声明仍然对导入 Foo 的客户端可见,因为编译器以不同的方式查找运算符,而不是在顶层查找其他所有内容。
从最后一条消息中:
这个讨论的总体结果是,它可能不值得为 Swift vNext 做任何聪明的事情:只需添加“仅实现导入”和可能的“导出导入”,然后暂时不用管其余部分。
推荐阅读
- google-apps-script - 如何在 Google Sheet 中以文本形式获取值(不执行公式)?
- c# - Toast 在 Xamarin Forms 项目中不起作用
- android - Android glide:裁剪 - 从图像底部截断 X 像素
- django - Django Admin:如何自定义 autocomplete_fields 宽度以适应内容?
- java - Android - 从 sqlite 获取字符串数据并使用 if 条件更改列表视图输入
- c# - 如何使用变量访问对象的成员
- javascript - 如何在对象数组上使用扩展运算符与 Math.min() 来查找扩展对象中值的最小值
- lisp - 即使列表中存在字符串,`member` 也会返回 `NIL`
- html - 减少@media 中的页面高度
- regex - 复合正则表达式,具有多个正则表达式组