Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for sending blocks to objc #54

Merged
merged 2 commits into from
Aug 29, 2017

Conversation

ojii
Copy link
Contributor

@ojii ojii commented Aug 21, 2017

This adds support for sending blocks to objc. It supports both "automagical python callable to objc block style" (which in non-trivial cases can segfault due to python GC) as well as "explicit create a block object style" through the rubicon.objc.Block.

Magical style (functions need to be fully annotated):

def myblock(arg1: arg1type, arg2: arg2type) -> return_type:
    ...

objc_instance.ObjcMethod_(myblock)

Explicit style:

from rubicon.objc import Block

myblock = Block(lambda a, b: ..., return_type, argtype1, argtype2)
objc_instance.ObjcMethod_(myblock)

Copy link
Collaborator

@dgelessus dgelessus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Overall everything looks good to me, but I have a couple of small questions/comments, see below.

Sorry that I haven't been able to review this sooner, I wasn't at my computer for the last few days.

@@ -1696,3 +1726,62 @@ def __call__(self, *args):
class ObjCBlockInstance(ObjCInstance):
def __call__(self, *args):
return self.block(*args)


_NSConcreteGlobalBlock = ObjCClass("__NSGlobalBlock__")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The __NSGlobalBlock__ class isn't actually documented anywhere. _NSConcreteGlobalBlock is documented, but not required to be an Objective-C class (you're only supposed to use its address).

So the officially supported way to use this would be:

_NSConcreteGlobalBlock = (c_void_p * 32).in_dll(c, "_NSConcreteGlobalBlock")
# ... when setting the isa ...
self.literal.isa = addressof(_NSConcreteGlobalBlock)

(_NSConcreteGlobalBlock is declared as a void *[32] in Block.h.)

self.descriptor.reserved = 0
self.descriptor.size = sizeof(BlockLiteral)

encoding_for_ctype(restype)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This discards the return value from the encoding_for_ctype call - is this intentional? If so, it would be good to add a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like leftover debugging code from me.

@@ -235,7 +238,8 @@ def ctype_for_encoding(encoding):

def encoding_for_ctype(ctype):
"""Return the Objective-C type encoding for the given ctypes type."""

if isinstance(ctype, POINTER_TYPE):
return b'^' + encoding_for_ctype(ctype._type_)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be in the except KeyError block below, so that pointer types that are in _encoding_for_ctype_map are looked up there. For example POINTER(c_char) should encode as *, not as ^c.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants