【问题标题】:PyObjC and returning 'out' parameters (i.e. NSError **)PyObjC 并返回“输出”参数(即 NSError **)
【发布时间】:2010-12-04 12:06:36
【问题描述】:

我正在实现一个 ObjC 协议作为 PyObjC 类的混合。

这个协议定义了一个'out'参数。

我找不到任何好的文档来说明实现定义它的 ObjC 协议的 Python 类的行为方式。

我找到了这个mailing list thread,但其中的建议不起作用。他们说要返回一个 Python 列表,其中方法的返回值作为第一项,out 参数作为第二项。

我已经尝试过了,我得到的只是从 ObjC (<type 'exceptions.ValueError'>: depythonifying 'char', got 'tuple') 调用时出现的异常。

似乎 PyObjC 在 depythonifying 方法参数中严格遵守 ObjC 协议,这很好,但它并不能帮助我尝试修改输出参数。

这是 ObjC 协议:

#import <Foundation/Foundation.h>

@protocol TestProtocol <NSObject>

- (BOOL)testMethod:(NSError **)error;

@end

这是实现此协议的 Python 类:

from Foundation import *
import objc

NSObject = objc.lookUpClass("NSObject")
TestProtocol = objc.protocolNamed("TestProtocol")

class TestClass(NSObject, TestProtocol):

    def testMethod_(self, error):
        return True, None

问题:如何在 Python 中返回 ObjC 输出参数?

【问题讨论】:

    标签: cocoa pyobjc


    【解决方案1】:

    这个问题很老了,不知道你现在有没有整理出来,但你还没有回答,前段时间我还在纠结从Obj-C到Python的参数。您绝对应该尝试/研究以下几点:

    首先也是最简单的一点是:当您在 Objective-C 中使用 Python 实现该存根时,您必须指定 (NSError **) 是一个 out 参数: p>

    @interface MyObject : NSObject
    - (BOOL)testMethod:(out NSError **)error;
    @end
    

    我已经成功地使用它从 Python 调用自定义 Obj-C 方法。我相信 Python 方面不会获得正确的元数据。

    还有一个 signature 装饰器添加到您的 Python 方法定义中。您可以指定其中一个参数是 sig 中的 out 参数。这个PyObjC doc 提供了详细信息。

    @objc.signature('@@:io^@')
    

    另一件事是(你现在可能已经自己弄清楚了)如果你不想做 Objective-C 存根,你可以生成自己的元数据并粘贴一个 .bridgesupport文件到你的项目中。我不确定的唯一一件事(大事!)是如何确保该文件实际被读取。元数据本身非常容易编写——Apple 提供了一个名为 gen_bridge_metadata 的命令行实用程序,您可以手动完成(查看 /System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python /PyObjC/AppKit/PyObjC.bridgesupport)。该实用程序有一个man pageman 5 BridgeSupport 也提供信息。您应该阅读的另一个 Apple 文档是:Generating Framework Metadata

    更新供未来的读者使用:我找到了函数 objc.registerMetaDataForSelectorobjc.parseBridgeSupport,这两个函数都允许您使用 Python dicts(前一个函数)为您的方法添加元数据或 BridgeSupport 手册页中描述的 XML 格式(后者)。使用 registerMetaData... 的示例可在 pyobjc 源代码中找到:pyobjc/pyobjc-core/PyObjCTest/test_metadata*,我是通过此 pyobjc-dev 邮件列表 thread 发现的。

    【讨论】:

      【解决方案2】:

      我试过了,我得到的只是一个 从 ObjC 调用时出现异常 (: depythonifying 'char',得到 'tuple')。

      PyObjC 通常将错误作为元组的第二个元素传回。

      类似:

      response, error = object.someMethod_error_(foo) # leave off the error
      if not response:
          # process error
      

      看到你的更新...

      您要么必须深入研究元数据桥,并弄清楚如何在运行时将一些元数据应用到您的实现中以使其正常工作。

      或者,可能更简单,是从已编译的 Objective-C 存根类中子类化。

      即试试这个:

      @interface AbstractFoo : NSObject
      @end
      
      @implementation AbstractFoo
      - (BOOL) myMethod: (int) arg error: (NSError **) anError;
      {
          return YES;
      }
      @end
      

      然后,您应该能够从 Python 端继承 AbstractFoo 并且它可能“正常工作”。

      也许吧。

      (抱歉——自从我对 PyObjC 如此深入以来已经有一段时间了)

      【讨论】:

      • “PyObjC 通常将错误作为元组的第二个元素传递回去。”是的,这就是我的 Python 方法 (testMethod_) 正在做的事情。但是 PyObjC 在返回 ObjC 领域时不遵守此规则,并随后引发异常。我在互联网上看到的所有答案的混淆似乎源于从 Python 调用 ObjC 与从 ObjC 调用 Python 之间的区别。我对后者感兴趣。一个不像另一个。
      • 谢谢 bbum。我尝试创建一个 ObjC 存根类并从 Python 中继承它,就像你建议的那样,但我得到了同样的异常(“depythonifying 'char', got 'tuple'”)。你知道我在哪里可以找到一些关于如何开始使用桥接技术的文档吗?
      • 呃——真可惜。最好的办法是阅读源代码。这是我引导人们远离使用任何桥梁来进行 Cocoa 开发的几个原因之一,除非你真的真的需要混合来自所需语言的库......对不起,我不能提供更多帮助。
      • 很有帮助。非常感谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 2011-04-10
      相关资源
      最近更新 更多