Using Xamarin to create a binding library for some external code, I've encountered a problem where despite (as far as I can tell) implementing all of the selectors in a protocol, in Obj-C code, my delegate fails to pass a conformsToProtocol
check and, as a result, the code doesn't work.
Here's what the Objective-C header file looks like (https://github.com/janrain/jump.ios/blob/master/Janrain/JRCapture/Classes/JRCapture.h):
@protocol JRCaptureDelegate <NSObject>
@optional
- (void)engageAuthenticationDialogDidFailToShowWithError:(NSError *)error;
- (void)engageAuthenticationDidCancel;
- (void)engageAuthenticationDidSucceedForUser:(NSDictionary *)engageAuthInfo forProvider:(NSString *)provider;
- (void)engageAuthenticationDidFailWithError:(NSError *)error forProvider:(NSString *)provider;
- (void)captureSignInDidSucceedForUser:(JRCaptureUser *)captureUser
status:(JRCaptureRecordStatus)captureRecordStatus;
- (void)captureSignInDidFailWithError:(NSError *)error;
- (void)registerUserDidSucceed:(JRCaptureUser *)registeredUser;
- (void)registerUserDidFailWithError:(NSError *)error;
- (void)refreshAccessTokenDidSucceedWithContext:(id <NSObject>)context;
- (void)refreshAccessTokenDidFailWithError:(NSError *)error context:(id <NSObject>)context;
@end
And here's the part of the ApiDefinition.cs
that corresponds to it:
[Model, BaseType (typeof (NSObject))]
public partial interface JRCaptureDelegate {
[Export ("engageAuthenticationDidCancel")]
void EngageAuthenticationCancelled ();
[Export ("engageAuthenticationDidSucceedForUser:forProvider:")]
void AuthenticationSucceededForProvider (NSDictionary engageAuthInfo, string provider);
[Export ("captureSignInDidSucceedForUser:status:")]
void SignInSucceeded (JRCaptureUser captureUser, JRCaptureRecordStatus captureRecordStatus);
[Export ("registerUserDidSucceed:")]
void RegisterUserSucceeded(JRCaptureUser registeredUser);
[Export ("refreshAccessTokenDidSucceedWithContext:")]
void RefreshAccessTokenSucceeded(NSObject context);
//- (void)engageAuthenticationDialogDidFailToShowWithError:(NSError *)error
[Export ("engageAuthenticationDialogDidFailToShowWithError:")]
void DialogFailedToShow (NSError error);
//- (void)engageAuthenticationDidFailWithError:(NSError *)error forProvider:(NSString *)provider;
[Export("engageAuthenticationDidFailWithError:forProvider:")]
void AuthenticationFailedForProvider (NSError error, NSString provider);
//- (void)captureSignInDidFailWithError:(NSError *)error;
[Export("captureSignInDidFailWithError:")]
void SignInFailed (NSError error);
//- (void)registerUserDidFailWithError:(NSError *)error;
[Export("registerUserDidFailWithError:")]
void RegisterUserFailed (NSError error);
//- (void)refreshAccessTokenDidFailWithError:(NSError *)error context:(id <NSObject>)context;
[Export("refreshAccessTokenDidFailWithError:context:")]
void RefreshAccessTokenFailed (NSError error, NSObject context);
}
This compiles and appears to work just fine except I was having a problem with one particular method that didn't appear to want to call the methods in my delegate class. After a lot of digging (and learning Objective-C the hard way), I believe I have isolated the problem. In the library I'm binding, I have this:
if ([delegate conformsToProtocol:@protocol(JRCaptureDelegate)] &&
[delegate respondsToSelector:@selector(captureSignInDidSucceedForUser:status:)])
And with a little DLog
ing, I find that my delegate fails the conformsToProtocol
check (although it does pass the respondsToSelector
check).
So why does my class fail conformsToProtocol
when it does implement all the methods in the protocol. What am I missing here?
My class implementing the delegate that gets passed to the various methods that take a JRCaptureDelegate
just looks like this:
public class SignIn : JRCaptureDelegate
{
// overrides for each method
}
Okay, think I might have cracked it. I added the Adopts
attribute to my class (which is vaguely mentioned in various places in the Xamarin documentation, but not really suggested as something to do when creating a binding library). So now I have this:
[Adopts("JRCaptureDelegate")]
public class SignIn : JRCaptureDelegate
{
// overrides for each method
}
And it now passes the conformsToProtocol
check. I'm not sure why this isn't automatic since I'm implementing the JRCaptureDelegate interface/protocol.