Problem with creating bindings for a delegate. (unrecognized selector sent to instance)

Hi,

I’m trying to generate bindings for SocketRocket (a websocket implementation) with Cocoapods. I’m using the plugin for Eclipse (1.3.0.v201701151001-13) and 1.3.0-beta-2 in Gradle.

The generated SRWebSocket class seams to work fine. I’m able to open a connection to a websocket server, but the delegate interface SRWebSocketDelegate is not reachable from native code.

Here is the generated delegate interface:

@Generated
@Runtime(ObjCRuntime.class)
@ObjCProtocolName("SRWebSocketDelegate")
public interface SRWebSocketDelegate {
	@Generated
	@IsOptional
	@Selector("webSocket:didCloseWithCode:reason:wasClean:")
	default void webSocketDidCloseWithCodeReasonWasClean(SRWebSocket webSocket,
			@NInt long code, String reason, boolean wasClean) {
		throw new java.lang.UnsupportedOperationException();
	}

	@Generated
	@IsOptional
	@Selector("webSocket:didFailWithError:")
	default void webSocketDidFailWithError(SRWebSocket webSocket, NSError error) {
		throw new java.lang.UnsupportedOperationException();
	}

	@Generated
	@Selector("webSocket:didReceiveMessage:")
	void webSocketDidReceiveMessage(SRWebSocket webSocket,
			@Mapped(ObjCObjectMapper.class) Object message);

	@Generated
	@IsOptional
	@Selector("webSocket:didReceivePong:")
	default void webSocketDidReceivePong(SRWebSocket webSocket,
			NSData pongPayload) {
		throw new java.lang.UnsupportedOperationException();
	}

	@Generated
	@IsOptional
	@Selector("webSocketDidOpen:")
	default void webSocketDidOpen(SRWebSocket webSocket) {
		throw new java.lang.UnsupportedOperationException();
	}

	@Generated
	@IsOptional
	@Selector("webSocketShouldConvertTextFrameToString:")
	default boolean webSocketShouldConvertTextFrameToString(
			SRWebSocket webSocket) {
		throw new java.lang.UnsupportedOperationException();
	}
}

The method webSocketDidOpen(SRWebSocket webSocket) should be called while opening a connection. But in the native part the condition in the if block is false

[self _performDelegateBlock:^{
    if ([self.delegate respondsToSelector:@selector(webSocketDidOpen:)]) {
        [self.delegate webSocketDidOpen:self];
    };
}];

And when a new message is received,

- (void)_handleMessage:(id)message
{
    SRFastLog(@"Received message");
    [self _performDelegateBlock:^{
        [self.delegate webSocket:self didReceiveMessage:message];
    }];
}

throws an NSInvalidArgumentException

"-[test.websocket.TestWebsocket webSocket:didReceiveMessage:]: unrecognized selector sent to instance 0x1767c010"

TestWebsocket is the Implementation of SRWebSocketDelegate and was set as delegate in SRWebSocket before opening the connection:

public class TestWebsocket implements SRWebSocketDelegate {
	
	SRWebSocket websocket;

	public void open(String url) {
		if (websocket == null) {
			websocket = SRWebSocket.alloc();
		}
		websocket.initWithURL(NSURL.URLWithString(url));
		websocket.setDelegate(this);
		websocket.open();
	}

	public void close() {
		if (websocket != null) {
			websocket.close();
		}
	}

	public void send(String data) {
		if (websocket != null) {
			websocket.send(data);
		}
	}

	@Override
	public void webSocketDidReceiveMessage(SRWebSocket webSocket, Object message) {
		System.out.println(String.valueOf(message));
	}
}

Is this a bug or did I miss something important?

Most likely it is an issue with your ProGuard configuration. You can check the classes that will get into the app in build/moe/main/retro/output.

This is the code after proguard + retrolambda (which includes annotation propagation for NatJ).

You will most likely need to add rules to your proguard.append.cfg, like:

-keep package.of.SRWebSocketDelegate { *; };
-keep test.websocket.TestWebsocket { *; }; # might not be necessary

Thank you very much. Works fine now.