How to bind NSObject<EAAccessoryDelegate, NSStreamDelegate> in Monotouch? - binding

I am trying to bind a library and I have the following definitions on the .h files
#interface FbFAccessoryController : NSObject <EAAccessoryDelegate, NSStreamDelegate> {
id <FbFmobileOneDelegate> _delegate;
BOOL ScannerStarted;
}
#property (nonatomic, assign) id <FbFmobileOneDelegate> delegate;
#property (readonly, nonatomic) BOOL Version1b;
- (BOOL)mobileOneConnected;
#property (readonly, nonatomic) NSNumber *VoltIndex;
#property (readonly, nonatomic) BOOL ScannerStarted;
- (void)startScanner;
- (void)stopScanner;
- (void)checkBattery;
#end
For the Delegate
#class FbFAccessoryController;
#protocol FbFmobileOneDelegate <NSObject>
#required
- (void) mobileOneAccessoryController:(FbFAccessoryController *)mobileOne didChangeConnectionStatus:(BOOL)connected;
- (void) mobileOneAccessoryController:(FbFAccessoryController *)mobileOne didReceiveData:(NSData *)data;
#optional
- (void) mobileOneAccessoryController:(FbFAccessoryController *)mobileOne didReceiveError:(NSError *)error;
- (void) mobileOneAccessoryController:(FbFAccessoryController *)mobileOne didReceiveScannerStartStop:(BOOL)started;
- (void) mobileOneAccessoryController:(FbFAccessoryController *)mobileOne didReceiveDataSpin:(BOOL)started;
#end
I use ObjectiveSharpie to generate the bind but I when I try to compile I am getting the following error:
Type MonoTouch.ExternalAccessory.EAAccessoryDelegate' in interface list is not an interface
TypeMonoTouch.Foundation.NSStreamDelegate' in interface list is not an interface
And the code generated by objectivesharpie is:
public partial interface FbFAccessoryController : EAAccessoryDelegate, NSStreamDelegate {
[Export ("delegate", ArgumentSemantic.Assign)]
FbFmobileOneDelegate Delegate { get; set; }
[Static, Export ("sharedController")]
FbFAccessoryController SharedController { get; }
[Export ("Version1b")]
bool Version1b { get; }
[Export ("mobileOneConnected")]
bool MobileOneConnected { get; }
[Export ("VoltIndex")]
NSNumber VoltIndex { get; }
[Export ("ScannerStarted")]
bool ScannerStarted { get; }
[Export ("startScanner")]
void StartScanner ();
[Export ("stopScanner")]
void StopScanner ();
[Export ("checkBattery")]
void CheckBattery ();
}

The protocols should be decorated with the [Model] attribute, so you can implement them as if they were interfaces.
So, without using ObjectiveSharpie, it should look like this:
[BaseType (typeof(NSObject))]
interface FbFAccessoryController : EAAccessoryDelegate, NSStreamDelegate {
[Export ("delegate", ArgumentSemantic.Assign)]
FbFmobileOneDelegate Delegate { get; set; }
// ... //
}
Provided that the Delegates are defined like this:
[Model] //Look, no BaseType
interface EAAccessoryDelegate {
// [Export] what you need here
}
[Model]
interface NSStreamDelegate {
// [Export] what you need here
}

Related

How to bind Objective-C library with protocol and interface have same name

I'm binding a iOS SDK. But the Sharpie confused about this
#interface ALBBQuPaiService : NSObject<ALBBQuPaiService>
The last ALBBQuPaiService is #protocol ALBBQuPaiService
I have tried to change ApiDefinition code like this:
[Protocol(Name = "ALBBQuPaiService"), Model]
interface ALBBQuPaiServiceProtocol
{
...
}
[BaseType (typeof(NSObject), Name = "ALBBQuPaiService")]
interface ALBBQuPaiService : ALBBQuPaiServiceProtocol
{
// +(instancetype)sharedService;
[Static]
[Export ("sharedService")]
ALBBQuPaiService SharedService ();
// #property (nonatomic, weak) id<QupaiSDKDelegate> _Nullable delegte;
[NullAllowed, Export ("delegte", ArgumentSemantic.Weak)]
QupaiSDKDelegate Delegte { get; set; }
}
Finally, I got runtime time exception: unrecognized selector sent to instance 0x7c73f740
Any body can help me? Thanks in advance.
My SDK link
------------------- Update 1: add header file code -------------------------
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger,QupaiSDKWatermarkPosition){
QupaiSDKWatermarkPositionTopRight,
QupaiSDKWatermarkPositionBottomRight,
};
typedef NS_ENUM(NSInteger,QupaiSDKCameraPosition){
QupaiSDKCameraPositionBack,
QupaiSDKCameraPositionFront,
};
#protocol QupaiSDKDelegate;
#protocol ALBBQuPaiService
-(NSString *) getSdkConfigVersion:(NSString *) platformName
sdkVersion:(NSString *) sdkVersion;
-(void) getSdkConfigVersion:(NSString *) platformName
sdkVersion:(NSString *) sdkVersion
success:(void (^)(NSString *rpcResult))success
failure:(void (^)(NSError *rpcError))failure;
#property (nonatomic, weak) id<QupaiSDKDelegate> delegte;
#property (nonatomic, assign) BOOL enableBeauty;
#property (nonatomic, assign) BOOL enableImport;
#property (nonatomic, assign) BOOL enableMoreMusic;
#property (nonatomic, assign) BOOL enableVideoEffect;
#property (nonatomic, assign) BOOL enableWatermark;
#property (nonatomic, assign) CGFloat thumbnailCompressionQuality;
#property (nonatomic, strong) UIColor *tintColor;
#property (nonatomic, strong) UIImage *watermarkImage;
#property (nonatomic, assign) QupaiSDKWatermarkPosition watermarkPosition;
#property (nonatomic, assign) QupaiSDKCameraPosition cameraPosition;
- (UIViewController *)createRecordViewControllerWithMinDuration: (CGFloat)minDuration
maxDuration:(CGFloat)maxDuration
bitRate:(CGFloat)bitRate;
- (UIViewController *)createRecordViewController;
- (void)updateMoreMusic;
#end
#protocol QupaiSDKDelegate <NSObject>
- (void)qupaiSDK:(id<ALBBQuPaiService>)sdk compeleteVideoPath:(NSString *)videoPath thumbnailPath:(NSString *)thumbnailPath;
#optional
- (NSArray *)qupaiSDKMusics:(id<ALBBQuPaiService>)sdk;
- (void)qupaiSDKShowMoreMusicView:(id<ALBBQuPaiService>)sdk viewController:(UIViewController *)viewController;
#end
#interface ALBBQuPaiService : NSObject<ALBBQuPaiService>
+(instancetype)sharedService;
#property (nonatomic, weak) id<QupaiSDKDelegate> delegte;
#end
Remember that all the obj-c protocol act as a abstract class I recommend to put "protocol, model and set base type as nsobject, another thing all the methods or properties maked as a "required" you need to specify it as Abstract.
[Protocol, Model]
[BaseType (typeof(NSObject))]
interface myAwesomeDelegate
{
[Abstract]
[Export(...)]
void myRequiredMethod(uint param1)
[Export(...)]
void anotherMethod()
}
I recommend to use the objective sharpie tool it support .framework files using version 3.X with the command framework bind -f myFramework.framework
for more info about it check https://developer.xamarin.com/guides/cross-platform/macios/binding/objective-sharpie/tools/ or also you can check in the xamarin Github bindings https://github.com/mono/monotouch-bindings, if you have any specific question about bindings please let me know

How to compare instances declared as id<protocol> in Objective-C

I have a class that has a property declared as type id that adheres to a protocol and I'd like to ensure equality for it.
How do check for value equality on an property declared as type id?
#interface MyClass : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) id<SomeProtocol> attribute;
#end
#implementation MyClass
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[MyClass class]]) {
return NO;
}
return [self isEqualToMyClass:(MyClass *) object];
}
- (BOOL)isEqualToMyClass:(MyClass *)rhsValue {
if (rhsValue == nil) {
return NO;
}
return
([self.name isEqualToString:rhsValue.name] &&
// Compiler produces error: Error:(90, 36) no known instance method for selector 'isEqual:'
[self.attribute isEqual:rhs.attribute]);
}
#end
SomeProtocol is defined as:
#protocol SomeProtocol <NSObject>
#end
Class that extends SomeProtocol:
#interface MyAttributeClass : NSObject <SomeProtocol>
#end
MyAttributeClass implements the protocol SomeProtocol and it has its own isEqual and when an instance of it is stored by MyClass in attribute, I'd like to be able to check that the values are equivalent.
It is MyAttributeClass that gets assigned into MyClass:
MyClass *myClass = [[MyClass alloc] init];
myClass.name = "HAL";
myClass.attribute = [[MyAttributeClass alloc] init];
Probably you forgot to import the header containing the protocol definition. (Instead of only having a forward declaration.) Add that in front of the implementation.

iOS - Set Derived Property

I have the following derived property:
SongWrapper.h
#property (nonatomic, strong) NSString *title;
SongWrapper.m
- (NSString *)title;
{
return self.songDocument.songAttributes.title;
}
I tried to set it like this:
self.songViewController.songWrapper.title = titleTextField.text;
Why doesn't this work and what are the best practices for setting a derived property?
You have to defined getter but not setter. You need to define setter as well.
//Getter
- (NSString *)title;
{
return self.songDocument.songAttributes.title;
}
//Setter
- (void)setTitle:(NSString *)title;
{
self.songDocument.songAttributes.title = title;
}

Elegant way to create protected/abstract/etc methods in Objective-c [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Objective-с doesn't have built-in method visibility like protected, private, abstract.
How to implement it like in Java?
Solution in my answer below
private method visibility - easily implemented inside .m files:
#interface SomeClass () <SomeProtocolForPrivateImplementation>
{
int _someVar1;
int _someVar2;
int _someVarN;
}
#property (nonatomic, readwrite) NSString *someProperty;
- (void)_somePrivateMethod;
#end
#implementation SomeClass
- (void)_somePrivateMethod
{
}
#end
protected and abstract method visibilities require Class Category, but it's not only one solution. You can use next model. For example you have abstract Data Model class which implements the basic mechanisms for working with some data, for example some synchronization. You need to create subclasses that will load the data in different ways. In java you can easily make it like this:
public abstract class AbstractDataModel
{
public abstract String getDataModelID();
protected void syncData()
{
// ... some data synchronization
}
}
public class DataModel extends AbstractDataModel
{
#Override
public String getDataModelID() {
// TODO Auto-generated method stub
return null;
}
}
But you can't do the same in Objective-сб you need to use Class Categories, it no so cool :( .
I found a way to do this in more elegant way using protocols:
In .h file:
#protocol ModelSubclassingProtocol;
#interface Model : NSObject
{
int _someVar;
}
#property (nonatomic, readonly) NSString *someProperty;
- (id)initWithDictionary:(NSDictionary*)info;
- (BOOL)updateFromDictionary:(NSDictionary*)info; // return TRUE if update has changes
- (void)reloadItems;
#end
// use protocol for subclasses
#protocol ModelSubclassingProtocol <NSObject>
#required
// all abstract methods here
- (Class)someAbstractMethod1;
+ (NSString*)someAbstractMethod2;
- (BOOL)someAbstractMethod3;
#optional
// all protected methods here
- (void)someProtectedMethod1;
- (BOOL)someProtectedMethod2;
#end
In .m file:
#define SUBCLASS ((id<ModelSubclassingProtocol>)self)
#interface Model () <SomeProtocolsForPrivateImplementation>
{
NSMutableArray *_somePrivateVar1;
}
#property (nonatomic, readwrite) NSString *someProperty1;
#end
#implementation RDModel
+ (id)alloc
{
// check subclassing protocol implementation
Protocol *protocol = #protocol(ModelSubclassingProtocol);
NSString *protocolName = NSStringFromProtocol(protocol);
NSString *className = NSStringFromClass(self.class);
NSAssert([self.class conformsToProtocol:protocol], #"\n\nERROR: \"%#\" must be conforms to protocol \"%#\".\nRecommended to use internal class extension in \"%#.m\", sample code:\n\n#interface %# () <%#>\n#end\n\n", className, protocolName, className, className, protocolName);
return [super alloc];
}
#pragma mark - Private
- (NSDictionary*)_synchronizeItems:(NSArray *)array
{
//... some implementation before
// use abstract methods here
NSString *itemIdentifier = [SUBCLASS itemIdentifier];
//... some implementation after
}
Sorry for bad english.

override property from superclass in subclass

I want to override an NSString property declared in a superclass. When I try to do it using the default ivar, which uses the the same name as the property but with an underscore, it's not recognised as a variable name. It looks something like this...
The interface of the superclass(I don't implement the getter or setter in this class):
//Animal.h
#interface Animal : NSObject
#property (strong, nonatomic) NSString *species;
#end
The implementation in the subclass:
//Human.m
#implementation
- (NSString *)species
{
//This is what I want to work but it doesn't and I don't know why
if(!_species) _species = #"Homo sapiens";
return _species;
}
#end
Only the superclass has access to the ivar _species. Your subclass should look like this:
- (NSString *)species {
NSString *value = [super species];
if (!value) {
self.species = #"Homo sapiens";
}
return [super species];
}
That sets the value to a default if it isn't currently set at all. Another option would be:
- (NSString *)species {
NSString *result = [super species];
if (!result) {
result = #"Home sapiens";
}
return result;
}
This doesn't update the value if there is no value. It simply returns a default as needed.
to access the superclass variables, they must be marked as #protected, access to such variables will be only inside the class and its heirs
#interface ObjectA : NSObject
{
#protected NSObject *_myProperty;
}
#property (nonatomic, strong, readonly) NSObject *myProperty;
#end
#interface ObjectB : ObjectA
#end
#implementation ObjectA
#synthesize myProperty = _myProperty;
#end
#implementation ObjectB
- (id)init
{
self = [super init];
if (self){
_myProperty = [NSObject new];
}
return self;
}
#end

Resources