c# - Xamarin 中的 Objective-c 绑定(bind)问题

标签 c# ios binding xamarin.ios xamarin

我正在努力让我的第一个 Xamarin 绑定(bind)工作。我正在尝试创建 FlatUIKit 库的绑定(bind):https://github.com/Grouper/FlatUIKit .

我设法创建了上述项目的胖静态库(通用.a)。 我使用 Objective Sharpie 为我生成了 ApiDefinition.cs。 我使用该 ApiDefinition.cs 在 Xamarin 中创建了一个 BindingProject(稍作修改以使项目编译)。 我使用了那个新的 .dll 并在一个新项目中尝试了它。 从该 .dll 调用方法可以正常工作并编译。但是,我在运行时遇到问题。对 FlatUI_UIColor 进行的所有静态调用都返回 null。这使得该 API 无法使用。

这是包含颜色的初始 .h:

@interface UIColor (FlatUI)

  • (UIColor *) colorFromHexCode:(NSString *)hexString;
  • (UIColor *) turquoiseColor;
  • (UIColor *) greenSeaColor;
  • (UIColor *) emerlandColor;
  • (UIColor *) nephritisColor;
  • (UIColor *) peterRiverColor;
  • (UIColor *) belizeHoleColor;
  • (UIColor *) amethystColor;
  • (UIColor *) wisteriaColor;
  • (UIColor *) wetAsphaltColor;
  • (UIColor *) midnightBlueColor;
  • (UIColor *) sunflowerColor;
  • (UIColor *) tangerineColor;
  • (UIColor *) carrotColor;
  • (UIColor *) pumpkinColor;
  • (UIColor *) alizarinColor;
  • (UIColor *) pomegranateColor;
  • (UIColor *) cloudsColor;
  • (UIColor *) silverColor;
  • (UIColor *) concreteColor;
  • (UIColor *) asbestosColor;

  • (UIColor *) blendedColorWithForegroundColor:(UIColor *)foregroundColor backgroundColor:(UIColor *)backgroundColor percentBlend:(CGFloat) percentBlend;

@end

下面是 Objective Sharpie 生成的绑定(bind):

[Category, BaseType (typeof (UIColor))]
public partial interface FlatUI_UIColor {

    [Static, Export ("colorFromHexCode:")]
    UIColor ColorFromHexCode (string hexString);

    [Static, Export ("turquoiseColor"), Verify ("ObjC method massaged into getter property", "/Users/jhondel/Projects/iOS Libraries/FlatUIKit/Classes/ios/UIColor+FlatUI.h", Line = 14)]
    UIColor TurquoiseColor { get; }

    [Static, Export ("greenSeaColor"), Verify ("ObjC method massaged into getter property", "/Users/jhondel/Projects/iOS Libraries/FlatUIKit/Classes/ios/UIColor+FlatUI.h", Line = 15)]
    UIColor GreenSeaColor { get; }

    /// ...

    [Static, Export ("blendedColorWithForegroundColor:backgroundColor:percentBlend:")]
    UIColor BlendedColorWithForegroundColor (UIColor foregroundColor, UIColor backgroundColor, float percentBlend);
}

在 ApiDefintion.cs 中,我去掉了验证。

如果有帮助,这是初始库的 .m:

@implementation UIColor (FlatUI)

// Thanks to http://stackoverflow.com/questions/3805177/how-to-convert-hex-rgb-color-codes-to-uicolor
+ (UIColor *) colorFromHexCode:(NSString *)hexString {
    NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    if ([cleanString length] == 3) {
        cleanString = [NSString stringWithFormat:@"%@%@%@%@%@%@",
                       [cleanString substringWithRange:NSMakeRange(0, 1)],[cleanString substringWithRange:NSMakeRange(0, 1)],
                       [cleanString substringWithRange:NSMakeRange(1, 1)],[cleanString substringWithRange:NSMakeRange(1, 1)],
                       [cleanString substringWithRange:NSMakeRange(2, 1)],[cleanString substringWithRange:NSMakeRange(2, 1)]];
    }
    if([cleanString length] == 6) {
        cleanString = [cleanString stringByAppendingString:@"ff"];
    }

    unsigned int baseValue;
    [[NSScanner scannerWithString:cleanString] scanHexInt:&baseValue];

    float red = ((baseValue >> 24) & 0xFF)/255.0f;
    float green = ((baseValue >> 16) & 0xFF)/255.0f;
    float blue = ((baseValue >> 8) & 0xFF)/255.0f;
    float alpha = ((baseValue >> 0) & 0xFF)/255.0f;

    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

+ (UIColor *) turquoiseColor {
    static UIColor *turquoise = nil;
    static dispatch_once_t dispatchToken;

    dispatch_once(&dispatchToken, ^{
        turquoise = [UIColor colorFromHexCode:@"1ABC9C"];
    });

    return turquoise;
}

知道为什么 FlatUI_UIColor.GreenSeaColor(和其他)返回 null 吗?

感谢您的帮助。

@jstedfast 评论后更新:

感谢您的回复。

我已经使用 makefile 构建了 fat 库 https://github.com/xamarin/monotouch-samples/blob/master/BindingSample/src/binding/Makefile。

它构建了一个通用库(它收集了 armv7 和 i386)。
当我在 Xamarin 的绑定(bind)项目中导入这个 .a 时,它会自动生成 LinkWith。就我而言:

[assembly: LinkWith ("libXMBindingLibrarySampleUniversal.a", LinkTarget.ArmV7 | LinkTarget.Simulator, ForceLoad = true)]  

库仅使用“UIKit”和“Foundation”,根据文档,不需要在 LinkWith 中指定。

生成的 .dll 看起来不错。我可以在我的示例项目中访问它的方法。我设法创建了一个带有标题的 FlatUIButton,并在运行模拟器时看到了标题。但是该按钮无法单击并且是黑色的,因为所有 FlatUI_UIColor.X 都返回 null。我真的不知道发生了什么。

最佳答案

如果/当它们不能 P/Invoke 到 native 库时,绑定(bind)方法通常会返回 null。所以问题可能是您在构建中根本没有与 native 库链接(或者您正在模拟器上运行,例如, native 库在 FAT 二进制文件中不支持 i386),或者您有错误的链接器标志。

有两种方法可以为 Xamarin.iOS 的 native 库指定链接器标志,但我将向您介绍我认为最简单的方法:

如果您使用的是 Xamarin Studio 并且您已经使用 Objective-C 绑定(bind)项目模板创建了一个项目,您只需添加 native 库(扩展名为 .a),Xamarin Studio 将创建一个新的源文件与 native 库具有相同的基本名称,但具有“.linkwith.cs”扩展名。

您需要做的是编辑该文件并进行所需的任何调整。

初始的 LinkWith 属性应该看起来像这样(这是根据内存,所以它可能不是 100% 准确):

[assembly: LinkWith ("libLibraryName.a", LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator, ForceLoad = true)]

如果库是c++,你需要添加:

IsCxx = true

您还可以指定它所依赖的框架:

Frameworks = "UIKit"

如果 native 库需要与其他 native 库链接,您可以使用 LinkerFlags 属性(字符串)指定它们。

(您真的只需要指定应用程序尚未链接的框架 - 因此您通常可以跳过 Foundation 和 UIKit,但这也没有坏处)

还有其他可以设置的属性,但我想不起来了,所以你可能想查看 docs获取更多可用属性(Google 可能会提供其他资源)。

关于c# - Xamarin 中的 Objective-c 绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22883497/

相关文章:

ios - UIWebView 从后台返回后在 iOS 7 上更改 contentSize

wpf - 绑定(bind)以显示 double 作为 int

c# - 何时取消 Hook Xamarin 自定义呈现器中的事件

iphone - XCode 4.4如何将文件永久添加到项目中

c# - 使用 NUnit 按顺序运行 TestFixtures

ios - 多选模式下的 UITableView 删除所选单元格中所有 subview 的背景颜色

mvvm - 自己的 DataTemplateSelector MVVM

SwiftUI - 结构绑定(bind)未按预期更新 UI

c# - 为什么在使用 MvxWpfSetup<Core.App> 作为 RegisterSetupType 时收到错误 CS0310

c# - 使用 angular-ui-router 避免 .NET MVC Controller 调用