Added support for varargs methods! I have tested this with arrayWithObjects method, and it works OK. Last argument must be nil in objective c, and in python we need to pass None insted of nil. Later internally in pyobjus, None is convered to NULL, otherwise we are getting segmentation fault

This commit is contained in:
ivpusic 2013-06-26 12:56:17 +02:00
parent ce5e0ce772
commit 5f58c2b1ac
9 changed files with 56 additions and 14 deletions

View File

@ -2,8 +2,6 @@
#include <objc/objc-runtime.h> #include <objc/objc-runtime.h>
#include <stdio.h> #include <stdio.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <Python.h>
#include <stdint.h>
static void pyobjc_internal_init() { static void pyobjc_internal_init() {
static void *foundation = NULL; static void *foundation = NULL;

View File

@ -10,7 +10,6 @@ include "common.pxi"
include "runtime.pxi" include "runtime.pxi"
include "ffi.pxi" include "ffi.pxi"
include "type_enc.pxi" include "type_enc.pxi"
from ctypes import c_void_p
from debug import dprint from debug import dprint
# do the initialization! # do the initialization!
@ -111,12 +110,16 @@ cdef class ObjcMethod(object):
cdef int is_static cdef int is_static
cdef object signature_return cdef object signature_return
cdef object signature_args cdef object signature_args
# this attribute is required for pyobjus varargs implementation
cdef object signature_default_args
cdef Class o_cls cdef Class o_cls
cdef id o_instance cdef id o_instance
cdef SEL selector cdef SEL selector
cdef SEL *selectors cdef SEL *selectors
cdef ObjcClassInstance p_class cdef ObjcClassInstance p_class
cdef int is_varargs
cdef object a
cdef object b
cdef int is_ready cdef int is_ready
cdef ffi_cif f_cif cdef ffi_cif f_cif
cdef ffi_type* f_result_type cdef ffi_type* f_result_type
@ -129,6 +132,7 @@ cdef class ObjcMethod(object):
self.name = None self.name = None
self.selector = NULL self.selector = NULL
self.selectors = NULL self.selectors = NULL
self.is_varargs = 0
def __dealloc__(self): def __dealloc__(self):
self.is_ready = 0 self.is_ready = 0
@ -199,7 +203,6 @@ cdef class ObjcMethod(object):
self.is_ready = 1 self.is_ready = 1
def __get__(self, obj, objtype): def __get__(self, obj, objtype):
if obj is None: if obj is None:
return self return self
@ -207,11 +210,35 @@ cdef class ObjcMethod(object):
self.o_instance = oc.o_instance self.o_instance = oc.o_instance
return self return self
def __call__(self, *args): def __call__(self, *args, **kwargs):
#if self.is_static: if len(args) > (len(self.signature_args) - 2):
# return self._call_class_method(*args) dprint("preparing potential varargs method...", type='i')
self.is_varargs = True
self.is_ready = False
# we are substracting 2 because first two arguments are selector and self
self.signature_default_args = self.signature_args[:]
num_of_signature_args = len(self.signature_args) - 2
num_of_passed_args = len(args)
num_of_arguments_to_add = num_of_passed_args - num_of_signature_args
for i in range(num_of_arguments_to_add):
self.signature_args.append(self.signature_args[-1])
# we need prepare new number of arguments for ffi_call
self.ensure_method()
return self._call_instance_method(*args) return self._call_instance_method(*args)
def _reset_method_attributes(self):
'''Method for setting adapted attributes values to default ones
'''
dprint("reseting method attributes...", type='i')
self.signature_args = self.signature_default_args
self.is_ready = False
self.ensure_method()
# this is little optimisation in case of calling varargs method multiple times with None as argument
self.is_varargs = False
def _call_instance_method(self, *args): def _call_instance_method(self, *args):
dprint('-' * 80) dprint('-' * 80)
@ -221,13 +248,11 @@ cdef class ObjcMethod(object):
dprint('--> return def is', self.signature_return) dprint('--> return def is', self.signature_return)
dprint('--> args def is', self.signature_args) dprint('--> args def is', self.signature_args)
cdef ffi_arg f_result cdef ffi_arg f_result
cdef void **f_args cdef void **f_args
cdef int index cdef int index
cdef size_t size cdef size_t size
cdef ObjcClassInstance arg_objcclass cdef ObjcClassInstance arg_objcclass
# allocate f_args # allocate f_args
f_args = <void**>malloc(sizeof(void *) * len(self.signature_args)) f_args = <void**>malloc(sizeof(void *) * len(self.signature_args))
if f_args == NULL: if f_args == NULL:
@ -275,6 +300,9 @@ cdef class ObjcMethod(object):
(<char **>val_ptr)[0] = <char *><bytes>arg (<char **>val_ptr)[0] = <char *><bytes>arg
elif sig == '@': elif sig == '@':
dprint('====> ARG', <ObjcClassInstance>arg) dprint('====> ARG', <ObjcClassInstance>arg)
if arg == None:
(<id*>val_ptr)[0] = <id>NULL
else:
ocl = <ObjcClassInstance>arg ocl = <ObjcClassInstance>arg
(<id*>val_ptr)[0] = <id>ocl.o_instance (<id*>val_ptr)[0] = <id>ocl.o_instance
# method is accepting class # method is accepting class
@ -301,6 +329,9 @@ cdef class ObjcMethod(object):
sig = self.signature_return[0] sig = self.signature_return[0]
dprint("return signature", sig, type="i") dprint("return signature", sig, type="i")
if self.is_varargs:
self._reset_method_attributes()
cdef id ret_id cdef id ret_id
cdef ObjcClassInstance cret cdef ObjcClassInstance cret
cdef bytes bret cdef bytes bret

View File

@ -53,3 +53,16 @@ print array.retainCount()
array.release() array.release()
print array.retainCount() print array.retainCount()
array_test = NSArray.arrayWithObjects_(text, newText, text, array, None)
print array_test.count()
array_new = NSArray.arrayWithObjects_(text, newText, None)
array_new = NSArray.arrayWithObjects_(None)
print array_new.count()
array_new = NSArray.arrayWithObjects_(None)
array_new = NSArray.arrayWithObjects_(text, None)
array_new = NSArray.alloc().initWithObjects_(None)
array_new = NSArray.alloc().initWithObjects_(text, None)
print array_new.objectAtIndex_(0).UTF8String()
array_new = NSArray.alloc().initWithObjects_(None)
print array_new.count()