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.
Dealing with a completion handler
-
I’m trying to make an notification system that will send a system notification when there’s a new topic on the most recent section of the forum. I’m trying to use the objc_util to schedule the function to the background threads. The function itself works, and sending the update to the background works, but the scheduler doesn’t repeat the function after the interval time. In: https://developer.apple.com/documentation/foundation/nsbackgroundactivityscheduler?language=objc
, it says that the scheduler won’t repeat if you don’t invoke the completion handler and send it the “all good flag” (integer 1).I have no idea how to send this flag to the completion handler. I’ve been through plenty of crashes to no avail lol. Here’s the code:
import requests as r from bs4 import BeautifulSoup as soup import notification from objc_util import * def update(_cmd,completion_handler):#not sure on number of args or types with open('most_recent.txt','rb') as f: most_recent=f.read() print('checking') #debug page=r.get('https://forum.omz-software.com/recent') page=soup(page.content,'html.parser') newest=page.select('meta')[8] content_name=newest.attrs.get('content') if bytes(content_name,'utf8') != most_recent: print(content_name)#debug with open('most_recent.txt','wb') as f: f.write(bytes(content_name,'utf8')) notification.schedule(message=f'Newest on the Pythonista Forum: {content_name}',action_url='https://forum.omz-software.com/recent',title='Pythonsita Forum') else:#debug notification.schedule(message='Nothing new...',title='Pythonista Forum')#debug #ObjCInstance(completion_handler).completion=1#doesnt work return scheduler=ObjCClass("NSBackgroundActivityScheduler").alloc().initWithIdentifier_('com.omz-software.Pythonista3.update_forums') scheduler.setInterval_(10)#more time when working scheduler.setTolerance_(5) scheduler.setRepeats_(True) scheduler.setQualityOfService_(25)#may change when working #not sure on restype or argtypes either block=ObjCBlock(update,restype=None,argtypes=[c_void_p,c_void_p]) scheduler.scheduleWithBlock_(block)
-
@mcriley821 did you check _objc_exception.txt file?
-
@cvp No exception file is created usually. I forgot what I did one time, but I got an exception once, and it said wrong selector sent to instance, during the first repeat. I’ve tried a ton of things though. Returning 1; 1,2,3 args; Different argtypes; different restypes;
The current code is one of the few that will actually run, and I feel it’s the least convoluted. -
@mcriley821 Is NSBackgroundActivityScheduler not only a MacOS object?
-
@cvp I just read that in the Apple docs, but how could I even create the class if that was true?
-
@mcriley821 I don't know, sorry. And strange because your block is called 🤔
-
Maybe @JonB has experienced this before?
-
Found a better solution @cvp by digging in @JonB objc_hacks.
import requests as r from bs4 import BeautifulSoup as soup from objc_util import * import notification import ctypes class _block_descriptor (Structure): _fields_ = [('reserved', c_ulong), ('size', c_ulong), ('copy_helper', c_void_p), ('dispose_helper', c_void_p), ('signature', c_char_p)] InvokeFuncType = ctypes.CFUNCTYPE(None, *[c_void_p, ctypes.c_int]) class _block_literal(Structure): _fields_ = [('isa', c_void_p), ('flags', c_int), ('reserved', c_int), ('invoke', InvokeFuncType), ('descriptor', _block_descriptor)] def update_forum(_cmd,_comp): comp=ObjCInstance(_comp) blk=_block_literal.from_address(_comp) blk.invoke(comp,1) with open('most_recent.txt','rb') as f: lst=f.readlines() most_recent,count=lst[0][:-1],lst[1] url='https://forum.omz-software.com/recent' page=r.get(url) page=soup(page.content,'html.parser') newest=page.select('meta')[8] content_name=newest.attrs.get('content') content_name=bytes(content_name,'utf8') post_count=newest.find_all('span')[2].attrs.get('title') post_count=bytes(post_count,'utf8') if content_name != most_recent or post_count != count: with open('most_recent.txt','wb') as f: f.writelines([content_name, b'\n', post_count]) notification.schedule( message=f'Newest on the Forum: {content_name.decode()}', action_url=url, title='Pythonista Forum', identifier='Forum_Updater' ) #else: #notification.schedule( message='Nothing new...', title='Pythonista Forum', identifier='Forum_Updater' ) return scheduler=ObjCClass('NSBackgroundActivityScheduler').alloc().initWithIdentifier_('Scheduler') scheduler.setRepeats_(True) scheduler.setInterval_(10*60) scheduler.setTolerance_(60) scheduler.setQualityOfService_(25) block=ObjCBlock(update_forum,restype=None,argtypes=[c_void_p,c_void_p]) scheduler.scheduleWithBlock_(block)
Sadly, it only works when in the app. It does free up the console though