Yes, the Nat/J bindings follow the Objective-C way to construct instances, and this prohibits the creation of such “anonymous” subclasses. Technically, it would be possible to support both options, e.g. for every method starting with init*() we could generate a constructor with the same parameters, that would call the correct alloc().init*() sequence on the Objective-C side behind the scenes, and only store the result from the init*() method to handle Objective-C class clusters correctly. We would be happy to implement this feature in a future release, the question is, how important is this feature to the community?
In my experience using anonymous classes to extend other classes in Java is an antipattern: in my experience such designs tend to be hard to maintain, and get messy over time. In our designs we try to restrict the use of anonymous classes to “closure” / “lambda function” like use cases, when an interface is implemented in such manner. These use cases work with the current Nat/J implementation, for example, in the following sample:
@Runtime(ObjCRuntime.class)
@ObjCProtocolName("CounterService")
public interface ICounterService {
@Selector("increment")
int increment();
@Selector("getCount")
int getCount();
}
@ObjCClassName("CounterService")
@RegisterOnStartup
public class CounterService extends NSObject {
protected CounterService(Pointer peer) {
super(peer);
}
private static ICounterService INSTANCE = new ICounterService() {
private int counter;
@Override
public int increment() {
return ++counter;
}
@Override
public int getCount() {
return counter;
}
};
@Selector("get")
public static ICounterService get() {
return INSTANCE;
}
}
There are of course exceptions, and there could be APIs where the natural way to go is to create an anonymous subclass of an abstract class, which is currently not possible with Nat/J based bindings. As I said before, we are open to implement this feature, I just added an issue to the backlog for it on GitHub. We will prioritize it based on the needs and interest of the community.
We just updated the mentioned samples for MOE 1.1, you can download them from here: https://github.com/migeran/moe-java-samples
Also, please note the special proguard.append.cfg that we added in the above sample project: ProGuard will remove the methods if they are not used from Java, only from Objective-C. To prevent this, you need to specify the appropriate -keep rules in your ProGuard configuration.
Generating constructors with correct alloc().init() code would be cool. Vote for it!
I need to create anonymous classes for testing purposes mostly. So, I can write more code, de-anonymise these classes, but it’s handy java feature that make my life easier.
If you are prepared to use the Xtend language (it’s awesome), I wrote some active annotations that do the work for you. For example:
@Alloc @Init
class MyViewController extends UIViewController {
@Accessors String name
@NSConstructor
def create(String name) {
this.name = name
}
}
The alloc and init annotations generate the (typed) methods, and the protected pointer constructor. Optionally you can also easily add constructors that call alloc and init for you. So the above class can be instantiated like this:
val myController = MyViewController.create('Hello world')