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.
How to Support Multipeer Connectivity ?
-
when delegate trip, Show Error box
Type Error ================ cannot build parament globals == locals =================== def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler):
-
Can you paste the actual traceback (if the debugger pops up, click the button in the corner to expand it, then tap Print Traceback). I seem to remember encountering a similar problem in the past. This comes from ctypes, but we need to know which argument is causing problepms.
-
@JonB not trackback info.
maybe the delegate define problem.
:(void(^)(BOOL accept, MCSession *session))invitationHandler
-
The error comes from ctypes callback.c. I suspect the issue is the ObjCBlock, the c code cannot convert the pointer it gets.
I know I encountered and solved this elsewhere, but can't find the solution, you might trydef advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler): print('invitation received') f= advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_ f.argtypes =[c_void_p]*4 f.restype = None f.encoding=b'v@:@@@@?' # also, try f.encoding=b'v@:@@@@' AdvertiserDelegate = create_objc_class('AdvertiserDelegate',methods=[advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_])
-
@JonB It's work. :-)
-
@JonB other problem.
ObjCInstance(invitationHandler).invoke(True,mySession)
No method found for selector "invoke"
print ObjCInstance(invitationHandler)
< NSStackBlock >
Traceback (most recent call last):
File "ctypes/callbacks.c", line 314, in 'calling callback function'
File "/private/var/mobile/Containers/Shared/AppGroup/A2331A94-5917-4220-83BB-A1CC1ED4E5A7/Pythonista3/Documents/Research/MCSrv.py", line 29, in advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler
ObjCInstance(invitationHandler).invoke(True,mySession)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 636, in getattr
cached_method = ObjCInstanceMethod(self, attr)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 860, in init
raise AttributeError('No method found for selector "%s"' % (self.sel_name))
AttributeError: No method found for selector "invoke:" -
It is possible you might need to do something like this
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.cbool,c_void_p]) class block_literal(Structure): _fields_ = [('isa', c_void_p), ('flags', c_int), ('reserved', c_int), ('invoke', InvokeFuncType), ('descriptor', _block_descriptor)]
then,
blk=block_literal.from_address(invitationHandler) blk.invoke(ObjCInstance(invitationHandler),True, ObjCInstance(mySession))
It seems as though the ObjCInstance does not handle invoke properly, since invoke is sort of special. The code abive creates the ctypes struct corresponding to the signature, i think, along with the hidden block argument, then calls it.
-
@JonB Thank you very much. I will try it later.
The other question.
I need call this objc function:- (NSInteger)write:(const uint8_t *)buffer
maxLength:(NSUInteger)length
I write this code:
buf=bytearray('sldfjksadklkadflksadjlsadkjsldfksadlf;sajflksddfjkl')
blen=len(buf)
outstream.write_maxLength_(id(buf),blen)=============
Traceback (most recent call last):
File "ctypes/callbacks.c", line 314, in 'calling callback function'
File "/private/var/mobile/Containers/Shared/AppGroup/A2331A94-5917-4220-83BB-A1CC1ED4E5A7/Pythonista3/Documents/Research/MCTest.py", line 40, in session_peer_didChangeState
outstream.write_maxLength_(id(buf),blen)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 897, in call
res = objc_msgSend(obj.ptr, sel(self.sel_name), *args)
ArgumentError: argument 3: <type 'exceptions.TypeError'>: wrong type - (NSInteger)write:(const uint8_t *)buffer
-
@wolf71
A way to check what objc_util thinks you need:restype,argtypes,encoding=objc_util.parse_types(outstream.write_maxLength_.encoding)
which gives
argtypes=[<class 'ctypes.c_void_p'>, <class 'ctypes.c_void_p'>, <class 'ctypes.c_char_p'>, <class 'ctypes.c_ulong'>]
the first two are the hidden self/selector, so the arguments need to be convertible to a char_p and a long.
write_maxlength(b'hello',5)
works (python3), or probably just the string without bytesarray in py2.
buf=ctypes.create_string_buffer(10) buf.value=b'hello'
is another way.
-
@JonB The
b"stuff"
syntax is valid in Python 2 as well, and returns a normalstr
(since Python 2str
is 8-bit anyway). -
@JonB Thank you very much.
It's work !!!
-
I know this is an old thread, but I am desperately wanting to do this in my app. I have copied the code from what was given and it got the two to print seeing each other. After the big section of server and browser side with the correction what needs to be done to get this working and communicating in an app?
-
I am trying to get this to work, but the following just crashes Pythonista (latest beta). All fine if you uncomment the last line. Any ideas?
#coding: utf-8 from objc_util import * NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID = ObjCClass('MCPeerID') MCNearbyServiceAdvertiser = ObjCClass('MCNearbyServiceAdvertiser') myID = MCPeerID.alloc().initWithDisplayName('peer') advertiser = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myID, None, 'dev_srv')
-
Ah, enabled the fault handler and noticed that it was just the service type with an underscore... Nothing to see here, please move along.
-
I have put up the two pieces of code above on Github:
Advertiser
BrowserThey work fine on first run, but the advertiser/server always crashes on the second run.
It only crashes if there was a successful connection on the first run, otherwise it runs fine.
Fault handler provides only a semi-useful error:
Fatal Python error: Segmentation fault Current thread 0x000000016fffb000 (most recent call first): File "/var/containers/Bundle/Application/01E95FCB-DD81-45FB-B878-47D3C0FF9E35/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 682 in __del__
... which points to the last line in this objc_util code:
def __del__(self): # Release the ObjC object's memory: objc_msgSend = c['objc_msgSend'] objc_msgSend.argtypes = [c_void_p, c_void_p] objc_msgSend.restype = None objc_msgSend(self.ptr, sel('release'))
Changes I have tried to the code in this thread, with no effect:
- Added session
disconnect()
to the end - Added try/except to only create the delegate classes when they do not already exist
Any help debugging this would be much appreciated.
- Added session
-
You could try to figure out which object is crashing, by manually del'ing them, one at a time. (my guess - services are getting del'd before delegates). Then, add an extra retain() for the offending objects.
Alternatively, maybe try setDelegate_(None) on everything that takes a delegate, to disentangle things.
-
@JonB, thanks.
Trying to run incrementally more code after the crash to find the culprit failed, as Pythonista will crash if I execute just an empty file.
Setting delegates to None has not changed things.
Manually
del
eting either the session object or the advertiser object both cause a crash after a successful connect, but do not cause a crash if I do the deletes after running the server code without a connection. -
@JonB, as this is the code that gets run on an invite, which seems to be the crucial point causing the crashes, and as I understand next to nothing about it, I have to ask if there is anything you see that messes things up?
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_bool,c_void_p]) class block_literal(Structure): _fields_ = [('isa', c_void_p), ('flags', c_int), ('reserved', c_int), ('invoke', InvokeFuncType), ('descriptor', _block_descriptor)] # Advertiser Delegate def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler): print('invitation',peerID) blk=block_literal.from_address(invitationHandler) blk.invoke(ObjCInstance(invitationHandler),True, ObjCInstance(mySession))
-
@mikael said:
advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_
Hmm, okay:
can you print (console).retainCount()
for the advertiser and session objects, for the case when no invite happens, then after the invite occurs?What I am wondering is if something is getting released by the invitationHandler -- that bit of code is taking the block that is passed to the delegate method, turning it into an actual ObjCBlock, then invoking it.
One thing you could do is override the
__del__
method of the suspect ObjCInstances -- maybe set up logging to a file in your script, then insert a logger.debug(self), that way we can see which object is the culprit.Next, you could try first calling
retain()
on those instances -- that may cause a memory leak, but probably not a crash. -
Thank you.
Before a connection, both advertiser and session report a retainCount of 2.
After a connection has been established and closed, calling retainCount on either object crashes Pythonista.
Printing counts within the callback, before the invitation invoke gives these:
- Advertiser: 5
- Session: 2
And immediately after:
- Advertiser: 6
- Session: 4