当前位置: 首页 > 面试题库 >

如何创建符合Swift和Objective-C之间共享协议的类方法?

谭繁
2023-03-14
问题内容

我最近一直在学习Swift。

我决定编写一个混合的Swift / Objective-C应用程序,该应用程序使用两种语言实现的相同算法来完成计算密集型任务。

该程序将计算大量的质数。

我定义了一个计算对象的Swift版本和Objective-C版本都应该遵守的协议。

这些对象都是单例,因此我在Objective-C中创建了一个典型的单例访问方法:

+ (NSObject <CalcPrimesProtocol> *) sharedInstance;

整个协议如下所示:

#import <Foundation/Foundation.h>
@class ComputeRecord;

typedef void (^updateDisplayBlock)(void);
typedef void (^calcPrimesCompletionBlock)(void);

    @protocol CalcPrimesProtocol <NSObject>

- (void) calcPrimesWithComputeRecord: (ComputeRecord *) aComputeRecord
              withUpdateDisplayBlock: (updateDisplayBlock) theUpdateDisplayBlock
                  andCompletionBlock: (calcPrimesCompletionBlock) theCalcPrimesCompletionBlock;

    @optional //Without this @optional line, the build fails.
    + (NSObject <CalcPrimesProtocol> *) sharedInstance;

    @end

该类的Objective-C版本完全实现上述定义的方法,无需担心。

快速版本有一个方法:

  class func sharedInstance() -> CalcPrimesProtocol

但是,如果将该方法作为协议的必需方法,则会出现编译器错误“类型” CalcPrimesSwift不符合协议“ CalcPrimesProtocol”。

但是,如果我在协议中将单例类方法sharedInstance标记为可选,那么它将起作用,并且可以在我的Swift类或Objective-C类上调用该方法。

我在Swift类方法的定义中是否错过了一些微妙之处?考虑到我能够在Swift类或Objective-
C类上调用sharedInstance()类方法,这似乎不太可能。

您可以从Github下载该项目,然后查看是否需要。它称为
SwiftPerformanceBenchmark

。(链接)


问题答案:

在Objective-C中,我们总是在传递指针,而指针始终可以是nil。Objective-
C的程序员很多利用的事实,将消息发送给nil什么也没做,返回0/ nil/
NO。Swift的处理方式nil完全不同。对象要么存在(从不存在nil),要么不知道它们是否存在(这是Swift可选对象起作用的地方)。

因此,在Xcode 6.3之前,这意味着任何使用Objective-
C代码的Swift代码都必须将所有对象引用视为Swift可选对象。关于Objective-C的语言规则,并没有阻止对象指针成为nil

使用Swift的Objective-C协议,类等意味着什么,这是一个很大的混乱。我们必须选择非完美的解决方案。

给定以下Objective-C协议:

@protocol ObjCProtocol <NSObject>

@required + (id<ObjCProtocol>)classMethod;
@required - (id<ObjCProtocol>)instanceMethod;
@required - (void)methodWithArgs:(NSObject *)args;

@end

我们可以接受方法定义为包含隐式解包的可选内容:

class MyClass: NSObject, ObjCProtocol {
    func methodWithArgs(args: NSObject!) {
        // do stuff with args
    }
}

这样可以使生成的代码更干净(我们永远不必在体内拆包),但是,我们始终会面临“发现nil的同时拆开可选包装”错误的风险。

或者,我们可以将方法定义为真正的可选方法:

class MyClass: NSObject, ObjCProtocol {
    func methodWithArgs(args: NSObject?) {
        // unwrap do stuff with args
    }
}

但这给我们留下了很多混乱的代码。

Xcode 6.3解决了此问题,并为Objective-C代码添加了“可空性注释”。

新引入的两个关键字是nullablenonnull。它们在为Objective-C代码声明返回类型或参数类型的地方使用。

- (void)methodThatTakesNullableOrOptionalTypeParameter:(nullable NSObject *)parameter;
- (void)methodThatTakesNonnullNonOptionalTypeParameter:(nonnull NSObject *)parameter;
- (nullable NSObject *)methodReturningNullableOptionalValue;
- (nonnull NSObject *)methodReturningNonNullNonOptionalValue;

除了这两个注释关键字之外,Xcode 6.3还引入了一组宏,这些宏使将Objective-
C代码的大部分内容标记为容易nonnull(完全不带注释的文件被假定为nullable)。为此,我们NS_ASSUME_NONNULL_BEGIN在本节的顶部和NS_ASSUME_NONNULL_END我们要标记的底部使用。

因此,例如,我们可以将整个协议包装在该宏对中。

NS_ASSUME_NONNULL_BEGIN
@protocol CalcPrimesProtocol <NSObject>

- (void) calcPrimesWithComputeRecord: (ComputeRecord *) aComputeRecord
              withUpdateDisplayBlock: (updateDisplayBlock) theUpdateDisplayBlock
                  andCompletionBlock: (calcPrimesCompletionBlock) theCalcPrimesCompletionBlock;
+ (id <CalcPrimesProtocol> ) sharedInstance;

@end
NS_ASSUME_NONNULL_END

这与将所有指针参数和返回类型标记为的效果相同nonnull(有一些例外,如Apple的Swift博客中的此项记为)。

Xcode 6.3之前的版本

符合Objective-C协议的Swift类必须将该协议中的所有Objective-C类型都视为可选。

为了弄清楚这一点,我创建了以下Objective-C协议:

@protocol ObjCProtocol <NSObject>

@required + (id<ObjCProtocol>)classMethod;
@required - (id<ObjCProtocol>)instanceMethod;
@required - (void)methodWithArgs:(NSObject *)args;

@end

然后,创建一个Swift类,该类继承自NSObject并且声明自己与this兼容ObjCProtocol

然后,我继续键入这些方法名称,并让Swift为我自动完成方法,这就是我所得到的(我放入方法主体中,其余的则为自动完成):

class ASwiftClass : NSObject, ObjCProtocol {
    class func classMethod() -> ObjCProtocol! {
        return nil
    }

    func instanceMethod() -> ObjCProtocol! {
        return nil
    }

    func methodWithArgs(args: NSObject!) {
        // do stuff
    }
}

现在,如果需要,我们可以使用常规的可选选项(带有?)来代替这些自动解包的可选选项。编译器完全满意。关键是,尽管我们必须考虑使用的可能性nil,因为无法阻止Objective-
C协议的nil通过。

如果此协议是在Swift中实现的,我们将选择返回类型是否为可选,而Swift将阻止我们返回nil未定义非可选返回类型的方法。



 类似资料:
  • 本文向大家介绍Objective-C语言符合协议,包括了Objective-C语言符合协议的使用技巧和注意事项,需要的朋友参考一下 示例 以下语法表明类使用尖括号括起来的协议。 这意味着NewClass的任何实例都将响应其接口中声明的方法,但也将为的所有必需方法提供实现NewProtocol。 一个类也可以通过用逗号分隔来遵循多个协议。 就像遵循单个协议时一样,该类必须实现每个协议的每个必需方法以

  • 我尝试将名为的Swift协议导入到名为的Objective-C类中。 我从一个现有的Objective-C项目开始(我没有用xCode创建一个新的Swift项目,也没有发现如何在Xcode6中将我的Objective-C项目配置为一个Swift项目)。 在Apple文档中,他们说我必须在我的文件中包含名为的文件。但我不需要将其包含在文件中,而是包含在中。这会有问题吗? 当我尝试编译时,出现以下错误

  • 我正在为Minecraft创建一个插口插件,允许玩家使用某个命令追捕另一个玩家。 从现在开始,所有的变量都在类的顶部声明,这样它们就可以从onCommand方法中访问。但是,如果我这样做,插件将只适用于一个玩家,因为每个人的变量都是一样的,并且被每个使用命令的人覆盖(例如,所有玩家都将在命令上有一个冷却计时器,因为第一个玩家使用它)。我希望所有的变量都在onCommand方法中声明,这样变量的值对

  • 问题内容: 我知道Java,现在正在学习Objective-C。Java接口和Objective-C协议之间到底有什么区别? 问题答案: 首先,从Java的一位创建者那里对该主题进行了一些历史性的展望。接下来,维基百科在Objective- C协议中 提供了适度有用的部分。特别要了解的是,Objective- C支持 正式协议 (使用关键字明确声明,相当于Java接口)和 非正式协议 (仅一个或多

  • Objective-C允许定义协议,声明预期用于特定情况的方法。 协议在符合协议的类中实现。 一个简单的例子是网络处理类,它将具有一个协议,其中包含委托方法等方法,当网络URL提取操作结束,就会调用类。 协议的语法如下所示 - 关键字下的方法必须在符合协议的类中实现,并且关键字下的方法是可选的。 以下是符合协议的类的语法 - 的任何实例不仅会响应接口中特定声明的方法,而且还会为中的所需方法提供实现

  • 问题内容: 在Objective-C中: 在Swift中: 但是,将出现一条错误消息: 类型“ CellDatasDataSource”不符合协议“ NSObjectProtocol” 类型“ CellDatasDataSource”不符合协议“ UITableViewDataSource” 正确的方法应该是什么? 问题答案: 类型“ CellDatasDataSource”不符合协议“ NSOb