簡體   English   中英

如何創建符合Swift和Objective-C之間共享協議的類方法?

[英]How to create class methods that conform to a protocol shared between Swift and Objective-C?

我最近一直在學習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版本完全按照上面的定義實現方法,不用擔心。

swift版本有一個方法:

  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代碼添加了“Nullability Annotations”。

這兩個新引入的關鍵字是nullablenonnull nullable 這些用於您聲明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 (完全沒有注釋的文件被認為是nullablenullable )。 為此,我們使用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並聲明自己符合此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返回給沒有定義非可選返回類型的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM