首页 > 解决方案 > 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...

enter image description here

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

标签: swiftframeworks

解决方案


我曾尝试使用私有模块映射来隐藏内部框架,使其用户不可见A,但没有运气。可能与[SR-2896] 私有模块映射无法正常工作有关。

我想这是现​​在的预期行为。swift.org 论坛上有多个提案可以实现您想要的东西,例如命名空间 x 子模块或更相关的一个@_exported 和修复导入可见性

上一篇的相关部分:

今天的 Swift 设计得更像 Java、C# 或 Python,因为如果你在 Foo 的实现中导入 Bar,它不会影响导入 Foo 的客户端。或者,它不会让导入 Foo 的客户看到 Bar 的顶级名称。

  1. 您仍然需要 Bar,因为编译器不会跟踪您是否在 Foo 的公共接口中使用了它的一种类型。(这是上一节。)

  2. Bar 中的扩展仍然对导入 Foo 的客户端可见,因为编译器不区分扩展来自今天的位置。

  3. Bar 中的运算符声明仍然对导入 Foo 的客户端可见,因为编译器以不同的方式查找运算符,而不是在顶层查找其他所有内容。

从最后一条消息中:

这个讨论的总体结果是,它可能不值得为 Swift vNext 做任何聪明的事情:只需添加“仅实现导入”和可能的“导出导入”,然后暂时不用管其余部分。

我很高兴知道是否有解决方法,但似乎 没有。


推荐阅读