混合Objective-c项目中的Swift“名称空间”无效

时间:2017-09-28 11:28:10

标签: ios objective-c swift namespaces

我有一个用objective-c编写的自定义框架MyFramework,其中我在UIColor上的objective-c类别中定义了一个方法:

+ (instancetype)my_colorWithRed:(uint8_t)red 
                          green:(uint8_t)green 
                           blue:(uint8_t)blue 
                          alpha:(uint8_t)alpha NS_SWIFT_NAME(init(red:green:blue:alpha:));

我使用NS_SWIFT_NAME为其提供正确的Swift名称。但是,Swift名称的声明与UIColorUIKit上已存在的方法相同,即:

init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)

现在,如果我在我的主应用程序中添加一个Swift文件 - 一个混合的objective-c和swift项目,链接到MyFramework - 并写下以下内容:

UIColor(red: 1, blue: 0, green: 0, alpha: 1)

调用方法的UIKit版本。但如果我写:

MyFramework.UIColor(red: 1, blue: 0, green: 0, alpha: 1)

仍然会调用该方法的UIKit版本。

所以我想知道为什么:

  • 构建应用程序而不为方法添加模块名称前缀不会给我任何警告或错误,即使方法不明确。我的印象是,如果发生这种情况,我会收到警告。
  • 指定MyFramework范围,该方法无效。

在Swift文件中,我不需要导入UIKitMyFramework,因为它们已经通过Swift桥接头导入;不是直接的,而是通过一些头文件间接导入它们。这可能是造成这个问题的原因吗?或者是因为它是一个混合的Objective-c和Swift项目?或者是因为这是一个类别的方法?

更新

来自Tarun Tyagi的回答了解参数类型。 指定类型使其有效:

UIColor(red: UInt8(149), green: UInt8(45), blue: UInt8(152))

这会调用MyFramework中的方法。这意味着我最初在调用中使用Integers:

UIColor(red: 1, blue: 0, green: 0, alpha: 1)

匹配UIKit的{​​{1}}代替init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)的{​​{1}}。

如果我创建一个采用Int

的新类别方法
MyFramework

然后从主应用程序调用{​​{1}},调用与该方法匹配。

添加convenience init(red: UInt8, green: UInt8, blue: UInt8)+ (instancetype)my_colorWithIntRed:(NSInteger)red green:(NSInteger)green blue:(NSInteger)blue alpha:(NSInteger)alpha NS_SWIFT_NAME(init(red:green:blue:alpha:)); 以限定通话次数没有任何区别。匹配仅基于参数类型,无论它在哪个模块中定义。也就是说,调用:

UIColor(red: 1, blue: 0, green: 0, alpha: 1)

没有出错,UIKit中的方法仍然被调用。

如果我在MyFrameworkUIKit.UIColor(red: 1, blue: 0, green: 0, alpha: 1) 中创建的初始值设定项与MyFramework中的初始值完全匹配:

MyFramework

然后根本没有生成Swift版本。

如果我在UIColor的swift扩展中创建相同的方法而不是

UIColor

然后我收到预期的错误:

  

初始化程序'init(红色:绿色:蓝色:alpha :)'与Objective-C选择器'initWithRed:绿色:蓝色:alpha:'与使用相同Objective-C选择器的先前声明冲突

但是当我删除@obj只使Swift中的方法可用时,我没有得到任何错误,这表明Swift允许在不同模块定义的扩展中有冲突的方法名称。

所以我从我的主应用程序拨打这个电话:

UIKit.UIColor

但是我仍然没有得到关于模糊方法的错误,并且调用了+ (instancetype)my_colorWithFloatRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_SWIFT_NAME(init(red:green:blue:alpha:)); 版本。此外,符合条件:

@objc public convenience init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
    ...
}

再次没有区别。

所以我仍然不明白Swift中的隐式命名空间应该如何与扩展一起使用。似乎它不受支持。我在extensions上阅读了Swift编程指南,但没有提到这一点。

2 个答案:

答案 0 :(得分:2)

构建应用程序而不为方法添加模块名称前缀不会给我任何警告或错误,即使方法不明确。我的印象是如果发生这种情况我会收到警告

  

这似乎是 -

     

一个。它应该在Swift中翻译为使用UInt8而不是CGFloat,因此根据输入类型而不同。

     

B中。或者它不应该允许在init(red:green:blue:alpha:)内使用NS_SWIFT_NAME,因为它与现有的初始值设定项冲突。

     

A和B都没有发生,所以它似乎是一个错误。您应该提交雷达以进一步调查此事。

指定MyFramework以使该方法无效

  

UIColor不归您的自定义框架所有,您只是在扩展它。您有责任唯一地命名方法。   <{1}}中可能的名称为my_color(red:green:blue:alpha:),以使其唯一。

     

显然,您的命名NS_SWIFT_NAMEinit(red:green:blue:alpha:)标准初始化程序发生冲突,如果您没有收到编译器警告并且能够运行,UIKit变种会胜过您的自定义。< / p>

希望它有所帮助。

编辑1:参考 https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

在此处将其添加为屏幕截图,因为链接可能会在将来的版本中中断。

虽然引用是针对Objective-C而不是Swift扩展,但这对于UIKit扩展是有效的,因为到目前为止所有UIKit仍然是Objective-C。

答案 1 :(得分:0)

尝试使用独特的东西为框架类添加前缀。称之为MyFrameworkUIColor