Objective-C语法和C语法的结果不同

时间:2018-11-20 11:17:07

标签: ios objective-c

我有以下方法部分

- (NSString*) GetPathForFolder:(int)folder inDomains:(int) domains {
    id cls = objc_getClass("NSFileManager");
    SEL defaultManagerSelector = @selector(defaultManager);
    SEL urlsForDirectoryInDomainsSelector = @selector(URLsForDirectory:inDomains:);

    id fileMangerHandle = objc_msgSend(cls, defaultManagerSelector);

    //NSArray<NSURL *>* notUsedArray = [fileMangerHandle URLsForDirectory:folder inDomains:domains];
    NSArray<NSURL *>* resultArray = (NSArray<NSURL *>*) objc_msgSend(fileMangerHandle, urlsForDirectoryInDomainsSelector, folder, domains);
    return [resultArray lastObject].absoluteString;
}

使用[self GetPathForFolder:5 inDomains:1]调用此方法 返回file:///Applications/,这是错误的

当我取消对NSArray<NSURL *>* notUsedArray..行的注释后,我会得到一个不同且正确的值,该值恰好与来自的值相同

在我的C版本中我没有做的调用的target-c版本有什么作用?

更新

  1. 我正在使用objc_msgSend,因为最终会从C#中调用此方法,但是比起开始担心互操作部分,这更容易在Objective-c中首先尝试。
  2. 我使用sel_registerName是因为在C#中运行此程序时,我将必须进行自己的注册。

有关C#和Objective-c here之间的互操作的更多信息。而且,我要了解的Java版本是here

1 个答案:

答案 0 :(得分:1)

您不能像这样使用objc_msgSend,它不是可变参数函数,即使它的原型表明了这一点。编译器需要使用与该方法相同的调用约定。为此,它需要知道所有参数的确切类型。您可以通过将objc_msgSend转换为具有正确参数的函数指针类型来说明这一点。

因此,在这种情况下,您将使用以下内容:

typedef NSArray<NSURL *> *(*UrlsForDirectoryType)(id, SEL, NSUInteger, NSUIteger);
NSArray<NSURL *>* resultArray = ((UrlsForDirectoryType)objc_msgSend)(fileMangerHandle, urlsForDirectoryInDomainsSelector, folder, domains);

当然,typedef是可选的,但是那样会使整个内容更难以阅读。

要将其公开给其他编程语言,您还可以在Objective-C中编写常规的C函数并调用它们。比直接处理运行时要容易得多。