【问题标题】:Objective C classes within an iOS Swift-based dynamic framework基于 iOS Swift 的动态框架中的 Objective C 类
【发布时间】:2016-06-02 20:04:25
【问题描述】:

情况:

我有一个用 Swift 编写的 iOS 动态框架。我还有一堆用 Objective C 编写的类,我会在我的 Swift 类中使用它们(有些是公共的,有些是私有的)。 但是,我希望 Objective C 类不要暴露给使用我的框架的项目


我尝试过的:

伞头

据我了解,我应该在我的总括头文件中使用#import header.h 导入,通常是FrameworkName.h,然后确保我希望包含在我的 Swift 类中的所有 Objective C 头文件都被标记作为“公共”,在 Build Phases -> Headers 下。

但是,这样做会自动将使用我的框架的项目公开给框架使用的所有私有 Objective C 类。

模块映射(带有单独的模块)

正因为如此,我研究了如何使用模块映射,它记录在 here。我查看了其他用户的帖子,例如thisthis,以及this Github repo

我成功完成了以下工作:

//SharedClasses/module.modulemap
module SharedClasses {
}

//SharedClasses/module.private.modulemap
module SharedClasses.Private {
    header "header.h"
    export *
}

问题是在我的项目中(导入了这个框架),这个:

import Framework
import Framework.SharedClasses

是允许的,随后“隐藏的”Objective C 类就会暴露出来。也许这就是模块的工作方式?有没有办法让它们真正私有化?

模块映射(带有框架私有模块)

另外,我尝试在我的框架的根目录创建一个module.private.modulemap 文件,其内容如下:

explicit module Framework.Private {
    header "header.h"
    export *
}

然后在 MODULEMAP_PRIVATE_FILE 下将它链接到我的目标构建设置。但是,当我在框架的 Swift 类中执行 import Framework.Private 时,会引发编译器错误:

"没有这样的模块'Framework.Private'

我不明白为什么会出现这个错误。

模块映射(带有私有标头)

我注意到在Clang docs 中,提到了private 说明符:

带有私有说明符的标头不能从模块本身外部包含。

我的理解是,由于我框架中的所有 Swift 类都已经是模块 Framework 的一部分,如果我创建一个包含以下内容的 module.modulemap 文件:

framework module Framework {
    umbrella header "Framework.h"

    private header "header.h"

    export *
    module * { export * }
}

那么一切都应该正常工作! Objective C 头文件只能在模块中访问(即框架的 Swift 类),并且不会暴露给使用框架的任何项目。很酷,但它不起作用......编译器只是无法识别 Objective C 类。没有引发其他错误,但您不能使用标头,所以就像您一开始没有包含标头一样。 为什么?那么私有说明符是什么?


Soo,重申我原来的问题:

有什么方法可以在 iOS 动态框架中导入用于 Swift 类的 Objective C 标头,同时保持它们的私有性,并且不能从使用该框架的任何项目中访问?

感谢您的阅读,很抱歉发了这么长的帖子。这是漫长的一天(和夜晚)......

【问题讨论】:

  • 我自己也在经历同样的头痛。你有没有让它工作?一旦您将标头标记为私有,它就无法在框架内部进行访问,这是没有意义的。然后就像,那么“私人”的意义何在?我一遍又一遍地重复同样的问题。
  • @marcelli407 不,我最终没有让它工作。我希望苹果能在今年的某个时候做点什么。目前,我决定坚持使用 Objective C 框架。我会确保在这里发布任何进一步的发现/更新!
  • @Jason,我必须在我的框架内创建另一个目标,它只包含目标 C 类,然后在我需要它的最终框架的快速代码中导入该目标。这允许仅在您的框架内公开类。
  • 不确定开发人员是否可以访问 Objective C 目标。
  • 我也被困在这一点上,花了几个小时后也没有找到任何解决方案。查看bugs.swift.org/browse/SR-655,似乎使用框架的外部项目需要私有模块这一事实是一个错误。 “暴露关于私有依赖的知识也是一个错误,但我认为需要设计来指定应该发生什么。如果你有兴趣,让我们在 swift-dev 上讨论它。”

标签: ios swift module frameworks clang


【解决方案1】:

你可以从this link找到一些方法。

只需使用 module.modulemap 创建文件夹(例如PrivateA),其中包含您需要在 Swift 类中使用的所有对象头。 例如

module $(ModuleName)Private {
    header "header.h"
    export *
}

在 Swift 中, 你可以使用:import $(ModuleName)Private

所以,默认模块在使用import $(ModuleName) 时会排除这些标头。

从我的实验来看,测试项目也可以import $(ModuleName)Private,但是没有找到任何有用的代码。

还是试试这个吧。

【讨论】:

【解决方案2】:

快速的回答是你不能:) 即使你声明“私有”模块映射,它也可以始终由你的框架用户导入。请注意,这通常不是问题,尤其是开源。你只是说“这是一个内部模块,不要使用它”。

但是(总是有但是)——你可以有行为,有效地工作相同——允许你在相同的框架目标中使用你的 Objective-C 类,而不会将它们公开。它在闭源设置中工作 - 我有一个动态框架发送给外部各方,其目的是尽可能少地揭示其构造。

案例有点过于复杂,无法在此处粘贴所有内容。我正在为我的文章添加关于该主题的链接。这是一个普遍的想法:

  1. 使用 Swift 协议模拟您的 Objective-C 类(需要手动操作)
  2. 在您的 swift 代码中使用这些协议
  3. 在内部向 Objective-C 公开这些 Swift 协议(需要手动操作)
  4. ObjC 类采用这些协议
  5. 在 Swift 中创建并在 ObjC 中公开一个工厂,它将创建这些协议的实例
  6. 在工厂方法中创建,这将允许您注册具体类型,并将它们公开给 ObjC
  7. 在 Swift 工厂中通过 Objective-C 代码注册 ObjC 类型
  8. 使用工厂实例化 ObjC 类,而无需将 ObjC 实际暴露给 Swift(万岁;))

Creating Swift framework with private Objective-C members. The Good, the Bad, and the Ugly

Github example project

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 2018-07-02
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多