Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello β I'm @olemoritz on Twitter.
Help finding the value of an objc string constant...
-
Hey all...trying desperately to get this topic through the aggressive spam filter...crazily it seems like the name of the uikit constant I'm asking about is itself being flagged as spam.
Anyway...I'm putting spaces in between each word of the name just to fool the filter:
UI Collection Element Kind Section Header
Trying to find the actual string value of that constant...my usual methods to find a value via google, in both objective-c and swift docs, etc. have all failed. You can see the definition of the constant by googling the name.
Anyone have an idea how to pull the value? I need it to finish my pythonista'd wrapper of a collection view.
-
Little update...in desperation, I started scrounging around in objc_util.c for the name...and it looks like there actually are both:
UI CollectionElementKind SectionHeader
and
UI CollectionElementKind SectionFootersymbols defined in there...though they show up as ctypes._FuncPtr objects...attempting to call them without arguments, or with None as the argument, crashes pythonista.
So...anything I can do with those?
-
@shinyformica said:
UI CollectionElementKind SectionHeader
I fail to find anything useful. Earlier there was a thread where some trick was used to dig some of these values from the framework DLL, see if I can find it.
Just checking: Have you tried just using the
constant name as a string? -
@mikael indeed, that was the first thing I tried...unfortunately it didn't work. I actually think I am missing something obvious here. I can find where it is defined in objective-c, but the definition contains no actual string value, and I can find no place where a string value is specified:
NSString *const UI Collection ElementKind SectionHeader;
(as before, remove the spaces in the spammy name of the constant).
-
@shinyformica, I found this thread.
I do not understand enough of what is happening there, but your constants are included in the list that the code gives.
With:
addr = ctypes.c_void_p.in_dll(objc_util.c, 'UICollectionElementKindSectionFooter')
I get a pointer to something, but nothing legible.
-
@shinyformica, that was just a long way to say that we obviously need @dgelessus and @JonB for this, even if you were too polite to say it.
-
A step more π
from objc_util import * x = c.UICollectionElementKindSectionFooter
-
@mikael thank you, checking out that thread now...and yes I was secretly hoping one of the objc gurus on here would know what I was missing. I think what's happening here is that Apple is actually using the address of the NSString* and not any actual string value.
@cvp are you saying that I can just directly use the value I pull from objc_util.c.UI CollectionElementKindSectionHeader in the objc method call? With no translation?
-
@shinyformica Correct - these string constants are actually global variables of type
NSString *
, which means that they contain a pointer to the actual string object.To read the pointer from the global variable, you need to use
ctypes.c_void_p.in_dll(objc_util.c, "ConstantName")
, as @mikael already found above.objc_util.c.ConstantName
will "work" (it doesn't crash), but that treatsConstantName
as a function and not a variable, so it returns a function pointer (which will crash when you try to call it, because normal variables are not valid functions).The value returned by
in_dll
is a regular Objective-C object pointer (which points to theNSString
object), but as ac_void_p
object, so you need to cast it toObjCInstance
manually so that you can use it. Once you do that, you have a regularNSString
object with the value you're looking for.In short:
>>> objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, 'UICollectionElementKindSectionHeader')) <b'__NSCFConstantString': UICollectionElementKindSectionHeader> >>> objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, 'UICollectionElementKindSectionFooter')) <b'__NSCFConstantString': UICollectionElementKindSectionFooter>
Strangely, the value of both string constants is literally their name, so the approach suggested by @mikael (just pass the name of the constant as a string) should have worked. Maybe UIKit expects you to pass in the exact pointer, and not just any string with the same contents? (That would be quite strange though.)
(By the way, please do @-mention me if there's something where you think I can help. Sometimes I only skim the forums very quickly, so I might miss some questions by accident.)
-
@dgelessus thanks so much for the deep knowledge!
So now this whole thing is working! As it turns out a lot of this was a red herring.
In summary:
- It is perfectly legal to use the python string value "UICollectionElementKindSectionHeader" directly in the
registerClass_forSupplementaryViewOfKind_withReuseIdentifier_()
objc method, since it is converted to an NSString object implicitly. - The value returned by
ctypes.c_void_p.in_dll(objc_util.c, "UICollectionElementKindSectionHeader")
works as well, I assume since that c_void_p ends up being interpreted as an NSString object. - Of course,
objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, "UICollectionElementKindSectionHeader"))
works, and is probably "safest" since you get the actual value without having to guess, and it is turned into a correct type. - You cannot directly use the _FuncPtr value returned by
objc_util.c.UICollectionElementKindSectionHeader
but there might be some way to convert that _FuncPtr value (just doing actypes.cast(funcptr, ctypes.c_void_p)
does not work).
Now, the reason the whole thing was a red herring: collection views won't even bother to call the
collectionView_viewForSupplementaryElementOfKind_atIndexPath_()
method unless the flow layout object being used to layout the items has had itsheaderReferenceSize
property set to something other than the defaultCGSize(0,0)
...so even when I was successfully registering the class with the method to create section headers, it wasn't being called. - It is perfectly legal to use the python string value "UICollectionElementKindSectionHeader" directly in the
-
@shinyformica sorry to answer so late, but I wrote my post in my bed π and, anyway, I don't know anything about ObjectiveC. I think only gurus mentioned by @mikael could give you an explanation. This forum is marvelous, isn'it?
-
@shinyformica, whatβs up with your UICollectionView wrapper? Anything I could try?
-
@mikael it works...it isn't feature-complete, and I was unable to figure out how to consistently get the proper animation of items when they are moved to a new location (it doesn't always animate the properties of the moved cell in the right way, or the cell in the new location is displayed before the move animation happens).
Let me try to extricate the code which is unrelated to the implementation of the UICollectionView from the custom code for my specific purposes. Maybe someone can figure out why my end-move animation is wonky.