将代码更新为 Unified API 的提示

将较旧的 Xamarin 解决方案更新到统一 API 时,可能会遇到以下错误。

NSInvalidArgumentException 找不到情节提要错误

使用自动迁移工具将项目转换为统一 API 后,Visual Studio for Mac 的当前版本中会出现一个 bug。 更新后,如果窗体中收到错误消息:

Objective-C exception thrown. Name: NSInvalidArgumentException Reason: Could not find a storyboard named 'xxx' in bundle NSBundle...

可以执行以下操作来解决此问题,找到以下生成目标文件:

/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/2.1/Xamarin.iOS.Common.targets

在此文件中,需要找到以下目标声明:

<Target Name="_CopyContentToBundle"
        Inputs = "@(_BundleResourceWithLogicalName)"
        Outputs = "@(_BundleResourceWithLogicalName -> '$(_AppBundlePath)%(LogicalName)')" >

并向其添加 DependsOnTargets="_CollectBundleResources" 属性。 类似于下面这样:

<Target Name="_CopyContentToBundle"
        DependsOnTargets="_CollectBundleResources"
        Inputs = "@(_BundleResourceWithLogicalName)"
        Outputs = "@(_BundleResourceWithLogicalName -> '$(_AppBundlePath)%(LogicalName)')" >

保存文件,重新启动 Visual Studio for Mac,并清理并重新生成项目。 Xamarin 应很快发布此问题的修补程序。

有用的使用技巧

使用迁移工具后,仍可能会收到一些需要手动干预的编译器错误。 可能需要手动修复的一些事项包括:

  • 比较 enums 可能需要 (int) 强制转换。

  • NSDictionary.IntValue 现在返回一个 nint,有一个 Int32Value 可以改用。

  • nfloat不能标记const类型nint;static readonly nint是一种合理的替代方法。

  • 以前直接在命名空间中 MonoTouch. 的东西现在通常位于命名空间中 ObjCRuntime. (例如: MonoTouch.Constants.Version 现在 ObjCRuntime.Constants.Version)。

  • 序列化对象的代码在尝试序列化 nintnfloat 类型时可能会中断。 请务必检查迁移后序列化代码按预期工作。

  • 有时,自动化工具会错过条件编译器指令中的 #if #else 代码。 在这种情况下,需要手动进行修复(请参阅下面的常见错误)。

  • 使用手动导出的方法 [Export] 可能无法由迁移工具自动修复,例如,在此代码 snippert 中,必须手动将返回类型更新为 nfloat

    [Export("tableView:heightForRowAtIndexPath:")]
    public nfloat HeightForRow(UITableView tableView, NSIndexPath indexPath)
    
  • 统一 API 不提供 NSDate 和 .NET DateTime 之间的隐式转换,因为它不是无损失转换。 在强制转换为NSDate之前,防止与将 .NET DateTime 转换为本地或 UTC 相关的DateTimeKind.Unspecified错误。

  • Objective-C 类别方法现在在统一 API 中生成为扩展方法。 例如,以前使用 UIView.DrawString 的代码现在将在统一 API 中引用 NSString.DrawString

  • 使用 AVFoundation 类 VideoSettings 的代码应更改为使用 WeakVideoSettings 属性。 这需要一个 Dictionary,该属性可用作设置类的属性,例如:

    vidrec.WeakVideoSettings = new AVVideoSettings() { ... }.Dictionary;
    
  • NSObject .ctor(IntPtr) 构造函数已从公共更改为受保护(以防止不当使用)。

  • NSAction替换为 标准 .NET Action。 一些简单的(单参数)委托也已 Action<T>替换为 。

最后,请参阅 经典 v 统一 API 差异 ,在代码中查找 API 的更改。 搜索 此页面 有助于查找经典 API 及其已更新的内容。

注意

迁移后命名空间 MonoTouch.Dialog 保持不变。 如果代码使用 MonoTouch.Dialog,则应继续使用该命名空间 - 请勿更改为 MonoTouch.DialogDialog

常见编译器错误

下面列出了常见错误的其他示例,以及解决方案:

错误 CS0012:未引用的程序集中定义了类型“MonoTouch.UIKit.UIView”。

修复:这通常意味着项目引用尚未使用统一 API 生成的组件或 NuGet 包。 应删除并重新添加所有组件和 NuGet 包。 如果未修复此错误,则外部库可能尚不支持统一 API。

错误 MT0034:不能在同一 Xamarin.iOS 项目中同时包含“monotouch.dll”和“Xamarin.iOS.dll” - 显式引用“Xamarin.iOS.dll”,而“monotouch.dll”则由“Xamarin.Mobile,Version=0.6.3.0,Culture=neutral,PublicKeyToken=null”引用。

修复:删除导致此错误并重新添加到项目的组件。

错误 CS0234:命名空间“MonoTouch”中不存在类型或命名空间名称“Foundation”。 是否缺少程序集引用?

修复:Visual Studio for Mac 中的自动迁移工具应更新所有MonoTouch.FoundationFoundation引用,但在某些情况下,需要手动更新这些引用。 以前包含 MonoTouch的其他命名空间可能会出现类似的错误,例如 UIKit

错误 CS0266:无法将类型“double”隐式转换为“System.float”

修复:更改类型和强制转换为 nfloat。 对于具有 64 位等效项的其他类型(例如 nint,)也可能发生此错误

nfloat scale = (nfloat)Math.Min(rect.Width, rect.Height);

错误 CS0266:无法将类型“CoreGraphics.CGRect”隐式转换为“System.Drawing.RectangleF”。 存在显式转换(是否缺少强制转换?)

修复:将实例更改为RectangleFCGRectSizeF更改为CGSizePointF更改为CGPointusing System.Drawing;命名空间应替换为using CoreGraphics;(如果尚不存在)。

错误 CS1502:“CoreGraphics.CGContext.SetLineDash”的最佳重载方法匹配(System.nfloat, System.nfloat[])具有一些无效的参数

修复:将数组类型更改为 nfloat[] 显式强制转换 Math.PI

grphc.SetLineDash (0, new nfloat[] { 0, 3 * (nfloat)Math.PI });

错误 CS0115:“WordsTableSource.RowsInSection(UIKit.UITableView, int)”被标记为替代,但没有找到合适的替代方法

修复:将返回值和参数类型更改为 nint。 这通常发生在方法重写中,例如 onUITableViewSourceRowsInSectionNumberOfSectionsGetHeightForRowTitleForHeaderGetViewForHeader等。

public override nint RowsInSection (UITableView tableview, nint section) {

错误 CS0508:: WordsTableSource.NumberOfSections(UIKit.UITableView)返回类型必须为“System.nint”才能匹配重写成员 UIKit.UITableViewSource.NumberOfSections(UIKit.UITableView)

修复:当返回类型更改为 nint时,将返回值强制转换为 nint

public override nint NumberOfSections (UITableView tableView)
{
    return (nint)navItems.Count;
}

错误 CS1061:类型“CoreGraphics.CGPath”不包含“AddElipseInRect”的定义

修复:将拼写更正为 AddEllipseInRect. 其他名称更改包括:

  • 将“Color.Black”更改为 NSColor.Black.
  • 将 MapKit“AddAnnotation”更改为 AddAnnotations.
  • 将 AVFoundation“DataUsingEncoding”更改为 Encode.
  • 将 AVFoundation 'AVMetadataObject.TypeQRCode' 更改为 AVMetadataObjectType.QRCode.
  • 将 AVFoundation“Video设置”更改为 WeakVideoSettings.
  • 将 PopViewControllerAnimated 更改为 PopViewController.
  • 将 CoreGraphics “CGBitmapContext.SetRGBFillColor” 更改为 SetFillColor.

错误 CS0546:无法重写,因为“MapKit.MKAnnotation.Coordinate”没有可重写集访问器(CS0546)

通过子类化 MKAnnotation 创建自定义批注时,“坐标”字段没有 setter,只有 getter。

修复方法

  • 添加字段以跟踪坐标
  • 在“坐标”属性的 getter 中返回此字段
  • 重写 SetCoordinate 方法并设置字段
  • 使用传入坐标参数在函数中调用 SetCoordinate

该属性应与下面类似:

class BasicPinAnnotation : MKAnnotation
{
    private CLLocationCoordinate2D _coordinate;

    public override CLLocationCoordinate2D Coordinate
    {
        get
        {
            return _coordinate;
        }
    }

    public override void SetCoordinate(CLLocationCoordinate2D value)
    {
        _coordinate = value;
    }

    public BasicPinAnnotation (CLLocationCoordinate2D coordinate)
    {
        SetCoordinate(coordinate);
    }
}