如何在Swift中调用Objective C类方法

在我的Objective-C标头上,我具有以下类方法声明:

@interface WXMediaMessage : NSObject

    +(WXMediaMessage *) message;

我试图像下面这样调用此方法:

var message : WXMediaMessage = WXMediaMessage.message()

但这是行不通的。我已经设置了桥接头。

编辑:

如果我按所述方式调用方法,则会显示错误信息'message()' is unavailable: use object construction 'WXMediaMessage()'

如果我使用WXmediaMessage(),错误会消失。但是,如果在目标C中调用它将返回与[WXMediaMessage消息]相同的结果吗?

MYAPP_bridging_header.h

#ifndef MYAPP_bridging_header_h
#define MYAPP_bridging_header_h

#import "WXApi.h"
#import "WXApiObject.h"

#endif

WXApiObject.h代码段

@interface WXMediaMessage : NSObject

   +(WXMediaMessage *) message;

@end

WXApiObject.m

(It is an external api, so I can't see the content)
写作

我的意思是:但是为什么?

这就是我们所要问的。Matt的答案是正确的,因为重命名方法可以解决问题,但是我们仍然要问为什么。

答案是因为Swift实际上将便捷方法重新映射到构造函数。

因此,尽管我们必须在Objective-C中调用这样的方法:

[WXMediaMessage message];

在Swift中,我们应该只调用WXMediaMessage()在Objective-C中,这等效于调用:

[[WXMediaMessage alloc] init];

重要的是要注意,当我们使用Swift默认的初始化方法时,实际的工厂方法不会被调用。这将直接进行init而无需调用工厂包装器。但是最佳实践提示,我们的工厂方法应该只不过是[[self alloc] init];一个值得注意的建议可能是单例,但是如果我们有单例工厂方法,则应遵循Apple设置的模式,并用“ shared”前缀命名我们的工厂方法:

+ (instancetype)sharedMessage;

下面的Swift代码将完全有效:

let message = WXMediaMessage.sharedMessage()

但是,如果message不是单例,则它不应大于return [[self alloc] init];,这是我们通过以下Swift代码获得的结果:

let message = WXMediaMessage()

这就是错误消息告诉我们要做的事情:

'message()' is unavailable: use object construction 'WXMediaMessage()'

错误消息告诉我们使用默认的Swift初始化程序,而不是Objective-C工厂方法。这是有道理的。任何人都想要在Objective-C中使用工厂方法的唯一原因是因为它[[MyClass alloc] init]看起来很丑。我们所有的初始化仍然应该在init方法中完成,但是……而不是在我们创建的工厂方法中,因为我们不想看alloc] init]……


考虑以下Objective-C类:

@interface FooBar : NSObject

+ (instancetype)fooBar;

- (void)test;

@end

@implementation FooBar

- (instancetype)init {
    self = [super init];
    if (self) {
        NSLog(@"initialized");
    }
    return self;
}

+ (instancetype)fooBar {
    NSLog(@"initialized with fooBar");
    return [[self alloc] init];
}

- (void)test {
    NSLog(@"Testing FooBar");
}

@end

现在使用以下Swift代码:

let var1 = FooBar()
var1.test()

我们得到以下输出:

2014-11-08 10:48:30.980 FooBar[5539:279057] initialized
2014-11-08 10:48:30.981 FooBar[5539:279057] Testing FooBar

如我们所见,该方法fooBar从未被调用。但是,确实,如果您在构建Objective-C类时考虑到了良好的做法是正确的,那么这样命名的类方法绝对不能超过:

return [[self alloc] init];

而且您的init方法应该处理所有设置。

当我们使用不太简单的初始化器和工厂方法时,发生的事情变得更加明显。

考虑是否我们添加了一种用数字初始化类的方法:

@interface FooBar : NSObject

+ (instancetype)fooBarWithNumber:(int)number;
- (void)test;

@end

@implementation FooBar {
    int _number;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        NSLog(@"initialized");
    }
    return self;
}

- (instancetype)initWithNumber:(int)number {
    self = [self init];
    if (self) {
        NSLog(@"init with number: %i", number);
        _number = number;
    }
    return self;
}

+ (instancetype)fooBarWithNumber:(int)number {
    NSLog(@"fooBar with number: %i", number);
    return [[self alloc] initWithNumber:number];
}

- (void)test {
    NSLog(@"Testing FooBar (number: %i)", _number);
}

@end

此时,请注意,我们.h公开了fooBarWithNumber:方法,但未公开initWithNumber:方法。

现在让我们回到Swift代码:

let var1 = FooBar(number: 3)
var1.test()

Swift将我们的fooBarWithNumber:方法变成了一个初始化器:FooBar(number:Int32)

这是输出:

2014-11-08 10:57:01.894 FooBar[5603:282864] fooBar with number: 3
2014-11-08 10:57:01.894 FooBar[5603:282864] initialized
2014-11-08 10:57:01.895 FooBar[5603:282864] init with number: 3
2014-11-08 10:57:01.895 FooBar[5603:282864] Testing FooBar (number: 3)

我们的fooBarWithNumber:方法称为,后者调用initWithNumber:,后者调用init


因此,“ WHY”这个问题的答案是因为Swift将我们的Objective-C初始化程序和工厂方法转换为Swift风格的初始化程序。

为了进一步扩展,问题甚至不仅仅在于方法名称本身。它是方法名,类名和AND返回类型的组合。在这里,我们将其instancetype用作返回类型。如果使用instancetype或特定的类类型,则会遇到问题。但是请考虑一下:

@interface FooBar

+ (NSArray *)fooBar;

@end

并假定该类方法的某些有效实现与类名匹配,但返回类型与我们的类不匹配。

现在,以下方法是完全有效的Swift代码:

let fooBarArray = FooBar.fooBar()

由于返回类型与该类不匹配,Swift无法将其转换为类初始化器,因此我们的方法很好。

还值得注意的是,如果我们选择id作为方法的返回类型,则:

+ (id)fooBar;

Swift将让我们逃脱它……但是它会警告我们,我们的变量被推断为类型为“ AnyObject!”。并建议我们添加一个显式类型,因此建议这样做:

let var1: FooBar = FooBar.fooBar()

这将使我们能够做到这一点……但是最佳实践几乎可以肯定地建议您不要将其id用作返回类型。苹果公司最近才将几乎所有id返回类型都更改instancetype

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Swift类中从Objective C调用单例类方法?

如何在Swift中调用Objective-C类别方法

如何在Swift中调用Objective-C instancetype方法?

Swift 中的 Objective C 类方法调用

如何在Swift类中重写Objective-C类的抽象类级别方法?

如何从Swift调用Objective-C类的工厂方法?

Swift:如何从Objective-C调用类别或类方法

无法在Swift中调用特定的Objective-C类方法

如何在Swift中没有参数的情况下调用Objective-C`initFoo`方法?

从Objective-C调用Swift类方法

从Objective-C调用Swift类方法

如何在Framework目标中从Objective-C调用Swift代码?

如何在Objective C中的类方法上使用self

在Swift中重写Objective C类方法

如何在Objective-C中调用具有多个参数的Swift初始化方法

如何在C ++中的类中递归调用函数方法?

Objective-C如何调用Swift方法?

如何在 C++ 中调用类 A 的方法 1 来调用类 B 的方法 2?

如何在 C++ 中调用基类方法?

如何从Objective C项目App委托中调用Swift?

在objective c 类中使用delegate 调用swift 方法

从Objective-C类调用Swift方法的语法

如何在swift中从被调用的方法中识别调用方法

从Swift测试文件中调用Objective-C类

如何从其他Objective-C类调用方法?

如何在Swift / Objective C中从HTTP请求返回数据

如何在Objective-C和Swift中实现“ didSelectButtonInCellAtIndexPath:”?

如何在同一框架内的Objective-C中访问内部Swift类?

如何在不定义新类的情况下在 Swift 中实现 Objective-C