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.
ObjC: Scheduling a stream on a run loop
-
I have a stream that shows status open, and accepts bytes that I write to it, but the delegate handler callback is not firing. I suspect I might not be scheduling the stream on the run loop properly:
stream.scheduleInRunLoop_forMode_(NSRunLoop.mainRunLoop(), 0)
I am especially unsure about the forMode parameter, which is supposed to be NSDefaultRunLoopMode global varuable. What is the right value to use in Python?
-
NSDefaultRunLoopMode
is a global variable of typeNSRunLoopMode
, which is atypedef
forNSString *
. To get the value of that variable, you can do the following:NSDefaultRunLoopMode = ObjCInstance(c_void_p.in_dll(c, "NSDefaultRunLoopMode"))
Then you can pass that object in the
forMode
part of the method call.0
doesn't work because it's interpreted as aNULL
pointer, which probably isn't a valid argument here. -
@dgelessus, ”extra credit” for leading me to the ctypes documentation and equipping me to maybe solve the next similar case myself.
-
Ah, seems I cannot do any objc stuff on my own...
This time the issue is that NSInputStream’s read:maxLength: needs a pointer to a buffer for storing the data coming from the stream. I have played with various ideas, including the following:
buffer = bytearray(1024) buf_p = ctypes.c_void_p.from_buffer(buffer) read_len = stream.read_maxLength_(buf_p, 1024)
... but all I get is a crash on read. Any pointers? Thanks!
-
@mikael The
from_buffer
method doesn't do what you think it's doing.ctypes.c_void_p.from_buffer(buffer)
assumes thatbuffer
contains data for ac_void_p
, and gives you ac_void_p
backed by that data. Basically, it's not giving you a pointer tobuffer
, it's interpreting the start ofbuffer
as a pointer. Sincebuffer
starts out as all zeroes,buf_p
is a null pointer, so writing to it will crash.I'm not quite sure, but you might be able to just pass
buffer
directly into the method.ctypes
might convert it to a pointer automatically - it does that for (read-only)bytes
objects, I'm not sure if it works withbytearray
s as well.If not, you can use
ctypes.create_string_buffer
to create a newc_char
array of the given length. This array can definitely be passed into C functions/methods. To get the data out of the array (after you've read into it), you can use theraw
attribute (to get the entire data) or thevalue
attribute (to get everything up to the first zero byte - this is useful for C strings). -
@dgelessus, thanks! Plain bytearray did not work, but create_string_array did, and I was able to create a bytearray out of its contents with the number of bytes read that read:maxLength: returns.