Forum Archive

Help with blocks (again!)

filippocld

Hey community,
I need you help for a little objcutil script.
I wanna use Core Spotlight to index some results in spotlight (iOS 9)
I set the attributes and the item correctly but i'm having trouble with indexing cause i don't know how to "convert" the normal objc block to objcutil correctly.

I basically have this code for initializing it:

def handlr(_cmd,error):
    if error:
        print error

handler= ObjCBlock(handlr,restype=None,argtypes=[c_void_p,c_void_p])

defindex = index.defaultSearchableIndex()
defindex.indexSearchableItems_completionHandler_(item,handler)

But it crashes the app ( i assume my block doesn't respect some conditions)

The docs say this for the indexing an item:

- (void)indexSearchableItems:(NSArray<CSSearchableItem *> * _Nonnull)items
           completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler

Is there something i'm missing?
Thanks in advance for your help
Filippo

JonB

if you just use pass inside the handlr body, do you still crash?

what are you using for item... that looks like a tricky typedef to get right..

omz

Have you tried just passing None as the completion handler? The block is declared as nullable, so that should work. I would suspect that the actual problem is somewhere else, haven't had time to try this myself yet.

omz

I've played around with the CoreSpotlight framework a little bit, and the code below doesn't crash... It adds an item to the default index, which then shows up in Spotlight's search results. Tapping on the search result starts Pythonista, but that's pretty much it — as far as I can see, there's no easy way for you to do anything in response to a search result being opened, unless I make some changes in the app itself.

from objc_util import *

UUID = '1234abcd'
TITLE = 'Pythonista Spotlight Test'
TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla rhoncus rutrum ornare. Integer ac dolor.'

CoreSpotlight = NSBundle.bundleWithPath_('/System/Library/Frameworks/CoreSpotlight.framework')
CoreSpotlight.load()

CSSearchableItem = ObjCClass('CSSearchableItem')
CSSearchableIndex = ObjCClass('CSSearchableIndex')
CSSearchableItemAttributeSet = ObjCClass('CSSearchableItemAttributeSet')

idx = CSSearchableIndex.defaultSearchableIndex()
attr_set = CSSearchableItemAttributeSet.alloc().initWithItemContentType_('public.text')
attr_set.setTitle_(TITLE)
attr_set.setContentDescription_(TEXT)

item = CSSearchableItem.alloc().initWithUniqueIdentifier_domainIdentifier_attributeSet_(UUID, None, attr_set)

def handler_func(_cmd, error):
    print 'Completion handler called'
    if error:
        print ObjCInstance(error)

handler= ObjCBlock(handler_func, restype=None, argtypes=[c_void_p, c_void_p])
idx.indexSearchableItems_completionHandler_([item], handler)

item.release()
attr_set.release()

Your block looked fine btw, I haven't really changed that, so I suspect the crash came from somewhere else.

filippocld

Thanks for the code.
So, the crash was due to the item not in an nsarray (i initially solved it without your code) but it wasnt actually indexing it.
The problem was this: instead of attr_set.setTitle("HelloWorld") i wrote attr_set.title = "HelloWorld" -.- i am so stupid. Thanks for your help, Solved :-)

JonB

I wonder if it would be possible for __getattr__ and __setattr__ to check for the existence of a selector someproperty(), and also setSomeproperty_(value), and if both exist, then treat calls to someobj.someProperty=somevalue or someobj.someProperty as a call to the appropriate selector. It might help fix problems like these, and makes ObjCClasses a little more pythonic.

filippocld

It would be definitely cool :-)

omz

@JonB I've thought about that as well... I've actually already implemented __setattr__ in this way for the next build, so that someobj.someProperty = foo is equivalent to someobj.setSomeProperty_(foo).

The problem I see with __getattr__ is that this would break existing code. Something like foo = someobj.someProperty() would fail because the property value wouldn't be callable... I'm generally okay with breaking code during the beta, but I need to think about this a little more than for __setattr__ (which still allows the old syntax).