I'm using sharpie bind command to get API interfaces for my iOS library for xamarin
sharpie bind --namespace=XXX --sdk=iphoneos9.2 Headers/*.h
Have issues with #protocol bindings:
The type or namespace name `IProfileDelegate' could not be found. Are you missing an assembly reference?
This is how it's generated:
interface XLibrary : IProfileDelegate
{
[Wrap ("WeakProfileDelegate")]
[NullAllowed]
MB_ProfileDelegate ProfileDelegate { get; set; }
I understand that it creates empty ProfileDelegate then compiler or something fills it with methods BUT my issue is that IProfileDelegate not found.
#protocol ProfileDelegate <NSObject>
#required
- (void)GetProfileFinished:(NSString*)_data;
- (void)SetProfileFinished:(NSString*)_data;
#end
Difference here in I symbol (which is reserved for #protocols I guess).
How to make sharpie generate proper api definitions?
I'm able to remove all I prefixes and it compiles successfully but I'd rather fix it not to repeat this every time I need to update source library.
Thanks
Remember that all the obj-c protocol act as a interface or 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()
}
hope this will help you to fix your issue
According to the Objective Sharpie documentation:
In some cases these generated files might be all you need, however more often the developer will need to manually modify these generated files to fix any issues that could not be automatically handled by the tool (such as those flagged with a Verify attribute).
This means you will sometimes have to adjust the two generated files, ApiDefinitions.cs and StructsAndEnums.cs to fix issues, such as the one in this case.
You can read more about how bindings work for Objective-C protocols, which are similar to C# Interfaces, but not quite in the binding documentation.
Related
I am trying to update my Xamarin Mixpanel iOS bindings that I have here. While updating I figured I'd try re-enable a thing I had disabled before I continue to roll out updates all the way to the latest 5.0 release.
Current status is I am attempting to bind v3.6.2 (which is a little outdated) and I am having issues with the binding of some protocol/interface things. The source file that is being bound is MixpanelType.h.
A short example of this is
#protocol MixpanelType <NSObject>
- (BOOL)equalToMixpanelType:(id<MixpanelType>)rhs;
#end
#interface NSString (MixpanelTypeCategory) <MixpanelType>
#end
The generated code that comes out of objective sharpie looks like this,
// #protocol MixpanelType <NSObject>
/*
Check whether adding [Model] to this declaration is appropriate.
[Model] is used to generate a C# class that implements this protocol,
and might be useful for protocols that consumers are supposed to implement,
since consumers can subclass the generated class instead of implementing
the generated interface. If consumers are not supposed to implement this
protocol, then [Model] is redundant and will generate code that will never
be used.
*/[Protocol]
[BaseType (typeof(NSObject))]
interface MixpanelType
{
// #required -(BOOL)equalToMixpanelType:(id<MixpanelType>)rhs;
[Abstract]
[Export ("equalToMixpanelType:")]
bool EqualToMixpanelType (MixpanelType rhs);
}
// #interface MixpanelTypeCategory (NSString) <MixpanelType>
[Category]
[BaseType (typeof(NSString))]
interface NSString_MixpanelTypeCategory : IMixpanelType
{
}
I don't understand Category, Model, or Protocols in objective-c is so I am not entirely sure what it is trying to become. Based on the other things in MixpanelType.h it looks like the code is just trying to allow certain class types to exist.
The code is natively used in a method like this,
- (void)addGroup:(NSString *)groupKey groupID:(id<MixpanelType>)groupID {
which gets bound automatically to look like:
// -(void)addGroup:(NSString * _Nonnull)groupKey groupID:(id<MixpanelType> _Nonnull)groupID;
[Export ("addGroup:groupID:")]
void AddGroup (string groupKey, MixpanelType groupID);
I am unsure if MixpanelType is meant to be IMixpanelType and I am unsure if things like NSString_MixpanelTypeCategory are meant to exist.
Keeping it as above (but changing MixpanelType to `IMixpanelType) and attempting to compile I get the following errors:
Xam.Plugin.Mixpanel.iOS/NSString_MixpanelTypeCategory.g.cs(51,69,51,83): error CS0714: 'NSString_MixpanelTypeCategory': static classes cannot implement interfaces
Xam.Plugin.Mixpanel.iOS/NSString_MixpanelTypeCategory.g.cs(51,69,51,83): error CS0535: 'NSString_MixpanelTypeCategory' does not implement interface member 'IIMixpanelType.EqualToMixpanelType(IMixpanelType)'
Xam.Plugin.Mixpanel.iOS/NSString_MixpanelTypeCategory.g.cs(51,69,51,83): error CS0535: 'NSString_MixpanelTypeCategory' does not implement interface member 'INativeObject.Handle'
Xam.Plugin.Mixpanel.iOS/NSString_MixpanelTypeCategory.g.cs(51,69,51,83): error CS0535: 'NSString_MixpanelTypeCategory' does not implement interface member 'IDisposable.Dispose()'
The first error is odd as this isn't a static class.
The second error is odd and I can't get rid of it by implementing the method.
The third and fourth errors are odd because this class has a base type of NSString and I thought this would have been handled.
Any help on this so I can successfully bind the entire library without MixpanelGroups being disabled would be appreciated.
I have mobile applicaction using Xamarin Forms. I have also library something.framework written in Objective-C and sample project in XCode.
I need to use this library in cross-platform application. I have added native reference to this library at Xamarin.iOS project. I use dependency interface to manage button's action from Xamarin Forms into Xamarin-iOS. The thing is that Visual Studio is not connecting native reference to library with my code in class. Using directive is not accessing native library so I have many errors when I try to use methods form library. I have already read Microsoft's instructions about binding native libraries but not answers came.
How to solve this?
Here are logs from terminal when I have used Objective Sharpie:
Johns-Mac-mini:~ johnmiller$ sharpie bind
-output=InfColorPickerCustom -namespace=InfColorPickerCustom ~/Desktop/InfColorPicker/InfColorPicker/*.h -sdk=iphoneos12.1 Parsing 8 header files... In file included from /var/folders/_g/mb3qv73j16d_mdwzb8bf5hww0000gn/T/tmp765fc04f.h:2: /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorIndicatorView.h:19:1: warning: no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute] #property (nonatomic) UIColor* color; ^ /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorIndicatorView.h:19:1: warning: default property attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute] In file included from /var/folders/_g/mb3qv73j16d_mdwzb8bf5hww0000gn/T/tmp765fc04f.h:3: In file included from /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorPicker.h:60: /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute] #property (nonatomic) UIColor* sourceColor; ^ /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute] /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute] #property (nonatomic) UIColor* resultColor; ^ /Users/johnmiller/Desktop/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]
Binding... [write] ApiDefinitions.cs [write] StructsAndEnums.cs
Binding Analysis: Automated binding is complete, but there are a few APIs which have been flagged with [Verify] attributes. While the entire binding should be audited for best API design practices, look more closely at APIs with the following Verify attribute hints:
ConstantsInterfaceAssociation (200 instances):
There's no foolproof way to determine with which Objective-C interface an extern variable declaration may be associated. Instances of these are bound as [Field] properties in a partial interface into a nearby concrete interface to produce a more intuitive API,
possibly eliminating the 'Constants' interface altogether.
MethodToProperty (193 instances):
An Objective-C method was bound as a C# property due to convention such as taking no parameters and returning a value (non-void return). Often methods like these should be bound as properties to surface a nicer API, but sometimes false-positives can occur and
the binding should actually be a method.
StronglyTypedNSArray (42 instances):
A native NSArray* was bound as NSObject[]. It might be possible to more strongly type the array in the binding based on expectations set through API documentation (e.g. comments in the header file) or by examining the array contents through testing. For example,
an NSArray* containing only NSNumber* instances can be bound as NSNumber[] instead of NSObject[].
PlatformInvoke (3256 instances):
In general P/Invoke bindings are not as correct or complete as Objective-C bindings (at least currently). You may need to fix up the library name (it defaults to '__Internal') and return/parameter types manually to conform to C calling conventionsfor the target
platform. You may find you don't even want to expose the C API in your binding, but if you do, you'll probably also want to relocate the definition to a more appropriate class and expose a stronger type-safe wrapper. For P/Invoke guidance, see http://www.mono-
project.com/docs/advanced/pinvoke/.
InferredFromMemberPrefix (29 instances):
The name of this originally anonymous declaration was taken from a common prefix of its members.
Once you have verified a Verify attribute, you should remove it from the binding source code. The presence of Verify attributes intentionally cause build failures.
For more information about the Verify attribute hints above, consult the Objective Sharpie documentation by running 'sharpie docs' or visiting the following URL:
http://xmn.io/sharpie-docs 6 warnings generated.
Done. Johns-Mac-mini:~ johnmiller$
I have solved it. There was a need to use scope when using Objective Sharpie. Simple add "-scope ~/Desktop/InfColorPicker/InfColorPicker". Then Sharpie is generating small files.
When a method is declared in .h file is detected by intelisense and the warnings are not raised, when the method is used in .m file.
When a method is declared only in .m file, the intelisense doesn't detect it if is declared below the method where is being used.
To avoid the warnings there is a flag in xcode, but I prefer don't disable it.
There is any way to declare the methods in .m in order to be detected by intelisense and without the warning?
Thanks.
Two ways to fix it:
Either: Use a class extension to declare private methods at the top of the .m file:
#interface Foo ()
- (void)privateMethod;
#end
Or: Upgrade to Xcode 4.3.1, which contains a more recent version of clang. This newer version of the compiler does not need previously declared methods to call them in the same compilation unit.
Class extensions are still good for compatibility or to declare private properties, though.
You can use a category to declare additional methods on a class.
For instance, adding this at the top of your .m file:
#interface MyClass (PrivateCategory)
-(void)foo;
-(void)bar;
#end
will let Xcode know that MyClass additionally responds to foo and bar. The (PrivateCategory) tells the compiler that you're adding methods that should be "grouped" under the category PrivateCategory. You can pick whatever name you want, or even no name at all (although an "anonymous category" has slightly different semantics).
In Ruby, there's Modules and you can extend a class by "mixing-in" the module.
module MyModule
def printone
print "one"
end
end
class MyClass
include MyModule
end
theOne = MyClass.new
theOne.printone
>> one
In Objective-C, I find that I have a set of common methods that I want a number of Class to "inherit". What other ways can I achieve this without creating a common class and deriving all from that common class?
Shameless plug: ObjectiveMixin
It takes advantage of Objective-C runtime's capability of adding methods to a class in runtime (as opposed to categories, which are compile-time only). Check it out, it works pretty good and in a similar fashion to Ruby's mixins.
Edit: changes added because some people feel I am responsible for the limitations of Objective-C.
Short answer: you can't. Objective-C doesn't have the equivalent of Ruby mixins.
Slightly less short answer: Objective-C does have something with arguably the same flavour: protocols. Protocols (Interfaces in some other languages), are a way to define a set of methods an class that adopts that protocols is committing to implementing. A protocol doesn't provide an implementation though. That limitation prevents using protocols as an exact equivalent to Ruby mixins.
Even less short answer: However, the Objective-C runtime has an exposed API that lets you play with the dynamic features of the language. Then you step outside the language, but you can have protocols with default implementations (also called concrete protocols). Vladimir's answer shows one way to do that. At that point it seems to me you get Ruby mixins alright.
However, I am not sure I would recommend doing that. In most cases, other patterns fit the bill without playing games with the runtime. For example, you can have a sub-object that implement the mixed-in method (has-a instead of is-a). Playing with the runtime is OK, but has 2 drawbacks:
You make your code less readable as it requires readers to know a lot more than the language. Sure you can (and should) comment it, but remember that any necessary comment can be seen as an implementation defect.
You depend on that implementation of the language. Sure, Apple platforms are by far the most common ones for Objective-C but don't forget Cocotron or GnuStep (or Etoilé) which have different runtimes, which may or may not be compatible with Apple's on that respect.
As a side note, I state below that categories cannot add state (instance variables) to a class. By using the runtime API, you can lift that limitation too. This is beyond the scope of this answer however.
Long answer:
Two Objective-C features look like possible candidates: categories and protocols. Categories are not really the right choice here, if I understand the question properly. The right feature is a protocol.
Let me give an example. Suppose you want a bunch of your classes to have a specific ability called "sing". Then you define a protocol:
#protocol Singer
- (void) sing;
#end
Now you can declare that any of your own classes adopts the protocol the following way:
#interface Rectangle : Shape <Singer> {
<snip>
#end
#interface Car : Vehicle <Singer> {
<snip>
#end
By declaring that they adopt the protocol they commit themselves to implementing the sing method. For example:
#implementation Rectangle
- (void) sing {
[self flashInBrightColors];
}
#end
#implementation Car
- (void) sing {
[self honk];
}
#end
Then you use those classes for example like this:
void choral(NSArray *choir) // the choir holds any kind of singer
{
id<Singer> aSinger;
for (aSinger in choir) {
[aSinger sing];
}
}
Notice that the singers in the array don't need to have a common superclass. Notice also that a class can have only one superclass, but many adopted protocols. Notice finally that type checking is done by the compiler.
In effect, the protocol mechanism is multiple inheritance used for the mixin pattern. That multiple inheritance is severely limited because a protocol cannot add new instance variables to a class. A protocol only describes a public interface adopters must implement. Unlike Ruby modules it does not contain an implementation.
That's the most of it. Let's mention categories however.
A category is declared not in angle brackets, but between parenthesis. The difference is that a category can be defined for an existing class to expand it without subclassing it. You can even do so for a system class. As you can imagine, it's possible to use categories to implement something similar to mixin. And they were used that way for a long time usually as category to NSObject (the typical root of the inheritance hierarchy), to such an extent that they were called "informal" protocols.
It's informal because 1- no type checking is done by the compiler, and 2- implementing the protocol methods is optional.
There is no need today to use categories as protocols, especially because the formal protocols can now declare that some of their methods are optional with the keyword #optional or required (the default) with #required.
Categories are still useful to add some domain specific behavior to an existing class. NSString is a common target for that.
It's also interesting to point out that most (if not all) of NSObject facilities are in fact declared in a NSObject protocol. This means that it's not really compelling to use NSObject as a common superclass for all classes, though this is still commonly done for historical reasons, and well... because there is no drawback for doing so. But some system classes, such as NSProxy, are not NSObject.
You can literally mixin the code using #include. This is not advisable and is against all the religions in objective-c, however works perfectly.
Please, don't do it in the production code.
for example in the file:
MixinModule.header (should not be compiled or copied to the target)
-(void)hello;
MixinModule.body (should not be compiled or copied to the target)
-(void)hello{
NSLog(#"Hello");
}
in mixin class:
#interface MixinTest : NSObject
#include "MixinModule.header"
#end
#implementation MixinTest
#include "MixinModule.body"
#end
usage case:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]){
#autoreleasepool {
[[[MixinTest new] autorelease] hello];
}
return 0;
}
Please, don't do it in the production code.
This is my take on implementing Mixins in Objective-C, without using the Objective-C runtime directly. Maybe it's helpful to someone: https://stackoverflow.com/a/19661059/171933
I'm writing a Cocoa API for a project and the API takes a delegate. The protocol that I came up with declares all the methods as optional, but why would I do that instead of just documenting the delegate methods in a header file and taking a plain id as a parameter?
For the benefit of your users. If the object takes delegates conforming to some protocol and they pass something else in, the compiler can tell them. That isn't possible if you take an id and use a category as the delegate method interface.
Because having "all of these methods" optional isn't quite the same as permitting "anything you care to send".
It also produces code that is more usable in the IDE. For example if I'm looking at
#interface MyController : NSObject <FooBarDelegate> {
}
#end
I can command+double click in Xcode to jump to the definition of FooBarDelegate. With a category there's no formal declaration of intent to be a delegate.
Also, #required can be a problem for future plans with regard to backward binary compatibility and a new preferred method signature.