如何在Swift中消除警告?

136

我有一段代码会产生很多警告(已弃用的API)

使用clang*,我可以执行:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    ...
#pragma clang diagnostic pop

然而这种方法在Swift中不起作用。

如何在Swift中实现呢?

注意:我不想全局禁用警告,甚至不想在整个文件中禁用,我只想在源代码的特定部分禁用特定的警告。

不想使用条件编译(这是所谓重复问题的提议答案)。 我只想在不使用新API的情况下消除警告。


可能是Swift替代方案#pragma clang diagnostic的重复问题。 - zrzka
6
这不是重复问题。其他问题未能解答这个问题。 - Claus Jørgensen
@robertvojta 不,事实上,这些答案并没有说明没有其他方法来消除警告。 - Claus Jørgensen
@ClausJørgensen,它说-没有简单/复杂的宏,没有预处理器,在注释中_"Swift编译器不包括预处理器。相反,它利用编译时属性、构建配置和语言特性来实现相同的功能。因此,预处理指令在Swift中不被导入。"看起来Swift永远不会支持clang诊断宏,目前也没有内置的本地替代方案。还有什么需要吗?clang诊断宏没有其他替代方案。 - zrzka
3
这不是一个重复的问题。如果你因为未设置初始化器而收到警告,该怎么办? - NSTJ
显示剩余5条评论
5个回答

237
截至2023年,Xcode 15.x,Swift 5.x,共识是目前没有直接的方法来实现这一点。
如果苹果公司添加了这个功能,我会更新/编辑这个答案。
把它放在你的WWDC 2024的愿望清单上吧!

35
真糟糕,有时会失控。最起码很烦人。 - Isuru
4
我想将这个答案踩一百万次,但它确实非常好地回答了问题,所以点赞+1 :-) - deadbeef
4
那时候我已经感到非常烦躁,以至于决定重新构建整个东西。看来警告起了作用。 - Allison
2
@Isuru 大多数情况下应该修复,而不是忽略。 - kevin
3
太令人沮丧了!感谢您保持这个答案的更新。 - dwlz
显示剩余3条评论

87

在Swift中,没有通用的结构来消除弃用警告,但有一种解决方法可以应用于许多情况

假设您在类 Foo 上有一个 getLatestImage()方法,该方法使用已弃用的方法/类。

按照Daniel Thorpe的描述使用 @available 来消除方法内部的所有警告:

class Foo {
    @available(iOS, deprecated: 9.0)
    func getLatestImage() -> UIImage? {
        ...
    }
}

现在您想要调用方法getLatestImage()而不会出现弃用警告。您可以通过首先定义协议和扩展来实现:

private protocol GetLatestImage {
    func getLatestImage() -> UIImage?
}
extension Foo: GetLatestImage {}

然后调用方法而不会出现废弃警告。

如果fooFoo的实例:

(foo as GetLatestImage).getLatestImage() // no deprecation warning

如果你想调用Foo的静态属性/函数:
(Foo.self as GetLatestImage.Type).someStaticProperty

结果是你有使用已弃用 API 的 Swift 代码,而没有任何弃用警告。

那全局函数呢?我们也可以解决这个问题。假设我们有一个模块 X,其中包含了函数 foo,它被声明为 @available(iOS, deprecated: 13.0) func foo() -> Int

在这种情况下,我们可以通过使用协议和枚举来解决:

protocol Undeprecated {
    static func foo() -> Int
}
enum Deprecated: Undeprecated {
    @available(iOS, deprecated: 13.0)
    static func foo() -> Int { X.foo() }
}

现在可以使用 (Deprecated.self as Undeprecated.Type).foo() 来调用 foo() 而不显示弃用警告。


3
聪明啊,有点邪恶? :) 不过很好用。比如,可以用来抑制某些已经被弃用但是替代方案并未提供全部所需功能的AddressBook框架警告信息,非常适合这种使用情况。谢谢。 - Duncan Babbage
6
如果这个有效,我会送你一箱你最喜欢的饮料。您的思维非常出色,谢谢。 - John
1
@John,你给他送去那六瓶装了吗?:P 这太棒了。天才。谢谢。 - Baran Emre
1
很不幸,使用Xcode 14,这个解决方法不再起作用了。我收到了一个警告,类似于“‘DeprecationClass’对‘DeprecationProtocol’的一致性已被弃用”。 - thetrutz
1
@ThomasTempelmann 我会相应地调整答案! - Tammo Freese
显示剩余7条评论

43

实际上,您可以通过在封闭的逻辑结构(即函数/类型)中使用@available来抑制这些警告。

例如,假设您有一些使用AddressBook框架的代码,但是您正在构建针对iOS 9的应用程序。

@available(iOS, deprecated: 9.0)
func addressBookStatus() -> ABAuthorizationStatus {
    return ABAddressBookGetAuthorizationStatus()
}

自 Xcode 7.0.1 开始,这将防止内联警告被显示。


11
是的,但当你调用已经被标记为弃用的addressBookStatus()函数时,你会看到同样的警告。 - Valentin Shergin
4
小技巧:如果你想在整个类中将其静音,只需将这个小东西拍在你的类声明之上(例如:class ViewController: UIViewController)。 - Allison
2
@Sirens 然后每次调用这个类时,您都会看到这个警告 ☹️(至少在Xcode 8中)。 - Alexander Vasenin
1
那么,当我执行 if CGFloat(0).native is Float { … } 时,如何使用它来消除警告“从 'CGFloat.NativeType' (又名 'Double') 转换为不相关类型 'Float' 总是失败”?答案:我不使用这个,因为你没有回答问题。 - Slipp D. Thompson
这似乎不包括在其他应用程序中使用Swift的情况,例如,服务器端Swift。 - Chris Prince
显示剩余3条评论

9
我遇到了一个问题,它与类或结构体之外的顶层函数有关:
@available(*, deprecated)
func GetImage(url: URL) -> UIImage? { ... }

我曾经和苹果的一名工程师交流过,他告诉我你可以通过协议隐藏实现并将扩展标记为弃用。让我们看看它是如何工作的:

  1. 创建一个与要包装函数具有类似签名的协议。
  2. 在任何类或结构体的扩展中使用该协议。
  3. 将扩展标记为弃用。

扩展中的所有内容都不会引起弃用警告。

protocol ImageStoreProtocol {
    func imageFromURL(_ url: URL) -> UIImage?
}

class ImageStore {}

@available(*, deprecated)
extension ImageStore: ImageStoreProtocol {
    func imageFromURL(_ url: URL) -> UIImage? {
        return GetImage(url: url) // Warning does't show up
    }
}

因为这是官方的 Apple 技能传授,所以点个赞吧 :) - Anton Poderechin
1
但是如果你调用类ImageStore().imageFromURL(...),那么你会再次收到弃用警告。(Xcode 13.4.1) - thetrutz
我在协议符合性定义中收到警告消息。 - undefined

2

虽然目前没有办法在Swift中消除弃用警告,但从技术上讲,您可以通过编辑头文件来针对特定符号进行操作。

  • 复制废弃的符号名称
  • 选择文件>快速打开
  • 粘贴符号并按Enter

    确保在“快速打开”框中禁用了Swift图标

  • 选择文件>在Finder中显示

  • 必要时更改文件权限以允许编辑
  • 为该符号编辑弃用宏。有关参考,请参见周围的API。例如,将以下内容替换为:

__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_10, __IPHONE_3_0, __IPHONE_8_0)

使用以下内容:

__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0)

现在,您可以消除一个分散注意力的警告。

我知道,这很不好。但是,如果当前SDK中没有可替代的API,则应该是安全的。一旦出现新版本的Xcode,更改将被覆盖,然后您将再次看到警告。然后,您可以测试新的SDK和操作系统,以确保废弃的API仍然可用且未被替换。

如果您能想出任何缺点,请发表评论。


2
点赞你的机智,但这会让我感到有些不舒服 :P - Matt

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