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

Support mapping Objective-C classes to custom ObjCInstance subclasses #81

Merged

Conversation

dgelessus
Copy link
Collaborator

Yes, it's another type mapping registry. This is a replacement for ObjCClass._select_mixin, which is not extensible and not very efficient as it grows (as I noted in #70). The new system uses a mapping to keep track of which Python type corresponds to which Objective-C class, which is more efficient and allows easy addition of extra types. This is now used internally for ObjCProtocol and ObjC[Mutable](List|Dict)Instance, but theoretically it can also be used externally.

ObjCClass, ObjCMetaClass and ObjCBlockInstace are still special-cased in ObjCInstance.__new__. They cannot be registered using the new system, because there is no single Objective-C base class for all classes, metaclasses or blocks.

This is somewhat similar to the existing system for converting
type encodings to ctypes types.
Their description methods return nil, which previously caused a type
error when it was returned from __str__. ObjC[Meta]Class now have a
custom __str__, and ObjCInstance.__str__ now detects description
methods returning nil and raises a more useful exception.
Copy link
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

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

This looks really good. I'll approve it on the grounds that it looks solid as is, assuming the tests pass (still waiting on those... Travis really is getting flaky...)

I've got one note on the general API, but I'm not hugely fussed about it if you disagree.

@@ -1208,7 +1259,7 @@ def __new__(cls, object_ptr, _name=None, _bases=None, _ns=None):
if is_block:
cls = ObjCBlockInstance
else:
cls = cls._select_mixin(object_ptr)
cls = type_for_objcclass(libobjc.object_getClass(object_ptr))
Copy link
Member

Choose a reason for hiding this comment

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

Is there any reason that the is_block check couldn't be merged into type_for_objcclass?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, unfortunately. is_block is assigned at the very top of ObjCInstance.__new__, and is used to remember whether the object_ptr that was originally passed to the constructor was of type objc_block. That information would be lost otherwise, because object_ptr is cast to objc_id in the next line.

Even if that wasn't the case, type_for_objcclass takes a class pointer, and the block check happens on the instance pointer. And the reason why we have to rely on the type of the instance pointer at all is because there's no good way to tell at runtime whether an object is a block or not.

@dgelessus
Copy link
Collaborator Author

dgelessus commented Nov 11, 2017

Yeah, Mac Travis is as reliable as usual. Four of the five builds ran fine, the remaining one failed to brew update so I whacked it with the restart wrench a few minutes ago. The backlog is acceptable at the moment ("only" 200 builds), so you could wait for that one build to finish. Or just merge right away, I doubt the last build would fail if the others all ran fine.

@dgelessus
Copy link
Collaborator Author

Nevermind, the build ran just now. That was much quicker than I expected.

@freakboy3742 freakboy3742 merged commit de34e18 into beeware:master Nov 11, 2017
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.

2 participants