@@ -536,12 +536,12 @@ static bool _convert_type(char p_type, void *p_buffer, MCValueRef& r_value)
536536 return true ;
537537}
538538
539- static bool _get_method_description (Protocol *p_protocol, SEL p_selector, objc_method_description & r_desc)
539+ static bool _get_method_description (Protocol *p_protocol, SEL p_selector, BOOL p_instance, objc_method_description & r_desc)
540540{
541541 objc_method_description t_desc =
542- protocol_getMethodDescription (p_protocol, p_selector, NO , YES );
542+ protocol_getMethodDescription (p_protocol, p_selector, NO , p_instance );
543543 if (t_desc.types == nullptr )
544- t_desc = protocol_getMethodDescription (p_protocol, p_selector, YES , YES );
544+ t_desc = protocol_getMethodDescription (p_protocol, p_selector, YES , p_instance );
545545
546546 if (t_desc.types == nullptr )
547547 return false ;
@@ -674,6 +674,23 @@ static bool _get_informal_protocol_method_types(MCStringRef p_selector, MCArrayR
674674 return MCStringCopy (*t_types, r_types);
675675}
676676
677+ static MCHandlerRef _fetch_handler_for_selector (SEL p_selector, MCArrayRef p_mapping)
678+ {
679+ MCAutoStringRef t_selector;
680+ if (!MCStringCreateWithCString (sel_getName (p_selector), &t_selector))
681+ return nullptr ;
682+
683+ MCNewAutoNameRef t_key;
684+ if (!MCNameCreate (*t_selector, &t_key))
685+ return nullptr ;
686+
687+ MCValueRef t_handler;
688+ if (!MCArrayFetchValue (p_mapping, false , *t_key, t_handler))
689+ return nullptr ;
690+
691+ return static_cast <MCHandlerRef>(t_handler);
692+ }
693+
677694@implementation com_livecode_MCObjcFormalDelegate
678695- (id )initForProtocol : (Protocol *)aProtocol withHandlerMapping : (MCArrayRef)aHandlerMapping withContext : (MCValueRef)aContext
679696{
@@ -696,7 +713,8 @@ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
696713 // Return the method signature of the protocol method we have an LCB
697714 // implementation for. This causes forwardInvocation to be called.
698715 objc_method_description t_desc;
699- if (!_get_method_description (m_protocol, aSelector, t_desc))
716+ if (!_get_method_description (m_protocol, aSelector, YES , t_desc) &&
717+ !_get_method_description (m_protocol, aSelector, NO , t_desc))
700718 return nullptr ;
701719
702720 return [NSMethodSignature signatureWithObjCTypes: t_desc.types];
@@ -766,19 +784,7 @@ - (void)dealloc
766784
767785-(MCHandlerRef)handlerFromSelector : (SEL )aSelector
768786{
769- MCAutoStringRef t_selector;
770- if (!MCStringCreateWithCString (sel_getName (aSelector), &t_selector))
771- return nullptr ;
772-
773- MCNewAutoNameRef t_key;
774- if (!MCNameCreate (*t_selector, &t_key))
775- return nullptr ;
776-
777- MCValueRef t_handler;
778- if (!MCArrayFetchValue (m_handlers, false , *t_key, t_handler))
779- return nullptr ;
780-
781- return static_cast <MCHandlerRef>(t_handler);
787+ return _fetch_handler_for_selector (aSelector, m_handlers);
782788}
783789
784790-(BOOL )respondsToSelector : (SEL )aSelector
@@ -944,8 +950,10 @@ static bool __MCTypeInfoConformsToObjcTypeCode(MCTypeInfoRef p_typeinfo, const c
944950 return true ;
945951}
946952
947- static bool __HandlerConformsToMethodSignature (MCHandlerRef p_handler, const char * p_typecodes, MCValueRef p_context)
953+ static bool __HandlerConformsToMethodSignature (MCHandlerRef p_handler, const char * p_typecodes, bool p_is_instance, MCValueRef p_context)
948954{
955+ /* TODO: Check how things work with protocol class methods */
956+
949957 MCTypeInfoRef t_handler_typeinfo = MCValueGetTypeInfo (p_handler);
950958
951959 // Check return type, the first code in the signature
@@ -988,6 +996,10 @@ static bool __HandlerConformsToMethodSignature(MCHandlerRef p_handler, const cha
988996 }
989997 }
990998
999+ // Ensure all the parameters required by the typecode are present
1000+ if (t_handler_conforms)
1001+ t_handler_conforms = strlen (p_typecodes) == 0 ;
1002+
9911003 if (!t_handler_conforms)
9921004 {
9931005 return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateCallbackSignatureErrorTypeInfo ,
@@ -1004,7 +1016,7 @@ static bool __HandlerConformsToInformalProtocolMethod(MCHandlerRef p_handler, MC
10041016 MCAutoStringRef t_types;
10051017 if (!_get_informal_protocol_method_types (MCNameGetString (p_selector), p_protocol, &t_types))
10061018 {
1007- return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateCallbackSignatureErrorTypeInfo ,
1019+ return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateMappingErrorTypeInfo ,
10081020 MCSTR (" Invalid protocol definition for selector %{sel}" ),
10091021 " sel" , p_selector,
10101022 nullptr );
@@ -1014,7 +1026,7 @@ static bool __HandlerConformsToInformalProtocolMethod(MCHandlerRef p_handler, MC
10141026 if (!t_typecodes.Lock (*t_types))
10151027 return false ;
10161028
1017- return __HandlerConformsToMethodSignature (p_handler, *t_typecodes, p_context);
1029+ return __HandlerConformsToMethodSignature (p_handler, *t_typecodes, false , p_context);
10181030}
10191031
10201032static bool __HandlerConformsToProtocolMethod (MCHandlerRef p_handler, MCStringRef t_method, MCValueRef p_context, Protocol *p_protocol)
@@ -1025,16 +1037,44 @@ static bool __HandlerConformsToProtocolMethod(MCHandlerRef p_handler, MCStringRe
10251037
10261038 SEL t_proxy_selector = NSSelectorFromString ((NSString *)*t_selector_cfstring);
10271039
1040+ bool t_is_instance = false ;
10281041 objc_method_description t_desc;
1029- if (!_get_method_description (p_protocol, t_proxy_selector, t_desc))
1042+ if (!_get_method_description (p_protocol, t_proxy_selector, YES , t_desc))
1043+ t_is_instance = true ;
1044+
1045+ if (t_is_instance && !_get_method_description (p_protocol, t_proxy_selector, NO , t_desc))
10301046 {
1031- return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateCallbackSignatureErrorTypeInfo ,
1047+ return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateMappingErrorTypeInfo ,
10321048 MCSTR (" Protocol method %{method} not found" ),
10331049 " method" , t_method,
10341050 nullptr );
10351051 }
10361052
1037- return __HandlerConformsToMethodSignature (p_handler, t_desc.types , p_context);
1053+ return __HandlerConformsToMethodSignature (p_handler, t_desc.types , t_is_instance, p_context);
1054+ }
1055+
1056+ static bool __AllRequiredProtocolMethodsImplemented (MCArrayRef p_handler_mapping, BOOL p_instance, Protocol *p_protocol)
1057+ {
1058+ uindex_t t_out_count = 0 ;
1059+ objc_method_description *t_required_methods =
1060+ protocol_copyMethodDescriptionList (p_protocol, YES , p_instance, &t_out_count);
1061+ for (uindex_t i = 0 ; i < t_out_count; ++i)
1062+ {
1063+ if (_fetch_handler_for_selector (t_required_methods->name ,
1064+ p_handler_mapping) == nullptr )
1065+ {
1066+ MCAutoStringRef t_selector;
1067+ if (!MCStringCreateWithCString (sel_getName (t_required_methods->name ), &t_selector))
1068+ return false ;
1069+
1070+ return MCErrorCreateAndThrowWithMessage (kMCObjcDelegateMappingErrorTypeInfo ,
1071+ MCSTR (" No mapping found for required protocol method %{method}" ),
1072+ " method" , *t_selector,
1073+ nullptr );
1074+ }
1075+ t_required_methods++;
1076+ }
1077+ return true ;
10381078}
10391079
10401080extern " C" MC_DLLEXPORT_DEF
@@ -1066,6 +1106,12 @@ bool MCObjcCreateDelegateWithContext(MCStringRef p_protocol_name, MCArrayRef p_h
10661106 return false ;
10671107 }
10681108
1109+ // Check all the required protocol methods have callbacks implemented
1110+ if (!__AllRequiredProtocolMethodsImplemented (p_handler_mapping, YES , t_protocol))
1111+ return false ;
1112+ if (!__AllRequiredProtocolMethodsImplemented (p_handler_mapping, NO , t_protocol))
1113+ return false ;
1114+
10691115 com_livecode_MCObjcFormalDelegate *t_proxy =
10701116 [[com_livecode_MCObjcFormalDelegate alloc ] initForProtocol: t_protocol withHandlerMapping: p_handler_mapping withContext: p_context];
10711117
@@ -1177,12 +1223,16 @@ bool MCObjcCreateInformalDelegate(MCProperListRef p_foreign_handlers, MCArrayRef
11771223// //////////////////////////////////////////////////////////////////////////////
11781224
11791225MCTypeInfoRef kMCObjcDelegateCallbackSignatureErrorTypeInfo ;
1226+ MCTypeInfoRef kMCObjcDelegateMappingErrorTypeInfo ;
11801227
11811228bool MCObjcErrorsInitialize ()
11821229{
11831230 if (!MCNamedErrorTypeInfoCreate (MCNAME (" livecode.objc.DelegateCallbackSignatureError" ), MCNAME (" objc" ), MCSTR (" Could not create delegate" ), kMCObjcDelegateCallbackSignatureErrorTypeInfo ))
11841231 return false ;
11851232
1233+ if (!MCNamedErrorTypeInfoCreate (MCNAME (" livecode.objc.DelegateMappingError" ), MCNAME (" objc" ), MCSTR (" Could not create delegate" ), kMCObjcDelegateMappingErrorTypeInfo ))
1234+ return false ;
1235+
11861236 return true ;
11871237}
11881238
0 commit comments