2311


Objective-CのコードをSwiftから使用しようとしているのですが

[code]

    @interface HMCoreDataManager : NSObject
    // primitive
    - (NSArray *)objectsWithEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors predicate:(NSPredicate *)predicate error:(NSError **)error;
    
    // A
    - (NSArray *)objectsWithEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors error:(NSError **)error predicateFormat:(NSString *)format, ...;
    - (NSArray *)objectsWithEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate error:(NSError **)error;
    
    // B
    - (NSArray *)objectsWithEntityName:(NSString *)entityName error:(NSError **)error predicateFormat:(NSString *)format, ...;
    
    @end
    
[/code]

上のクラスの AのメソッドをSwiftから呼ぼうとすると

[code]

    error: extra argument in call
    
[/code]

というコンパイルエラーが

BのメソッドをSwiftから呼ぼうとすると

[code]

    error: argument 'predicateFormat' must precede argument 'error'
    
[/code]

というコンパイルエラーが発生します

いずれも可変引数を含むメソッドなのですが、Swiftから可変引数を含むObjective-Cメソッドを呼ぶ場合何か制約があるのでしょうか

それとも何か別の要因があるのでしょうか？


CC BY-SA 3.0
2014-12-21T00:32:36.927
2303
2014-12-22T17:30:06.793
2014-12-22T17:30:06.793
2741
2741
question
objective-c swift
SwiftからObjective-Cの可変引数を含むメソッドが使用できない


Swiftからは可変長引数のObjective-Cのメソッドを呼ぶことはできないようです。

なので一つの方法としては va_list, va_start, va_end
マクロ(C言語)をつかったオーバーロードメソッドを用意してそれを呼ぶ形にするみたいです。  
もちろんすでに可変長でないオーバーロードがあればそちらを利用すればよいと思います。

[**こちらに本家の方での同様の質問があります**](https://stackoverflow.com/questions/24195796/how-
do-you-call-an-objective-c-variadic-method-from-swift)。後述の書き換え例はこちらを参考にしています。  
[**こちらも同様の本家の質問で**](https://stackoverflow.com/questions/24374110/swift-call-
variadics-c-function-defined-in-objective-c)できないという回答ですが、[ **Apple Developer
Forums**](https://devforums.apple.com/message/983462#983462)で回答のリンクが張ってありました。（ライセンスに抵触すると嫌なのでこちらは転載しません。）

* * *

コード書き換えはちょっと自信ないのでミスがあるかもしれませんが概ね以下の様な感じでしょうか。  
（といっても、最初のリンク先を真似ただけです）

[code]

    // B
    - (NSArray *)objectsWithEntityName:(NSString *)entityName error:(NSError **)error predicateFormat:(NSString *)format, ...;
    
[/code]

であれば、

[code]

    // B
    - (NSArray *)objectsWithEntityName:(NSString *)entityName error:(NSError **)error predicateFormat:(NSString *)format args:(va_list)args
    
[/code]

を追加し、本体をこちらに記載する。

元の可変長引数は以下の様にマクロを利用したバージョンに書き換えられる

[code]

    - (NSArray *)objectsWithEntityName:(NSString *)entityName error:(NSError **)error predicateFormat:(NSString *)format, ...
    {
         va_list argp;
         va_start(argp, format);  // 可変長引数にアクセスを開始
         NSArray *objects = [objectsWithEntityName: entityName error:error format:format args:argp];
         va_end(argp); // 終了処理
    }
    
[/code]

swiftからは getVaListでvalistポインタを取得できるようですので argsの部分は以下の様に指定することができるようです。

[code]

    ... format:"%d%d%d%d" args: getVaList([1,2,3,4]))
    
[/code]


CC BY-SA 3.0
2014-12-21T05:26:28.420
2311
2014-12-21T05:26:28.420
2017-05-23T12:38:55.250
-1
728
2303
answer