将代码更新为 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 应很快发布此问题的修补程序。
有用的使用技巧
使用迁移工具后,仍可能会收到一些需要手动干预的编译器错误。 可能需要手动修复的一些事项包括:
比较
enum
s 可能需要(int)
强制转换。NSDictionary.IntValue
现在返回一个nint
,有一个Int32Value
可以改用。nfloat
不能标记const
类型nint
;static readonly nint
是一种合理的替代方法。以前直接在命名空间中
MonoTouch.
的东西现在通常位于命名空间中ObjCRuntime.
(例如:MonoTouch.Constants.Version
现在ObjCRuntime.Constants.Version
)。序列化对象的代码在尝试序列化
nint
和nfloat
类型时可能会中断。 请务必检查迁移后序列化代码按预期工作。有时,自动化工具会错过条件编译器指令中的
#if #else
代码。 在这种情况下,需要手动进行修复(请参阅下面的常见错误)。使用手动导出的方法
[Export]
可能无法由迁移工具自动修复,例如,在此代码 snippert 中,必须手动将返回类型更新为nfloat
:[Export("tableView:heightForRowAtIndexPath:")] public nfloat HeightForRow(UITableView tableView, NSIndexPath indexPath)
统一 API 不提供 NSDate 和 .NET DateTime 之间的隐式转换,因为它不是无损失转换。 在强制转换为
NSDate
之前,防止与将 .NETDateTime
转换为本地或 UTC 相关的DateTimeKind.Unspecified
错误。Objective-C 类别方法现在在统一 API 中生成为扩展方法。 例如,以前使用
UIView.DrawString
的代码现在将在统一 API 中引用NSString.DrawString
。使用 AVFoundation 类
VideoSettings
的代码应更改为使用WeakVideoSettings
属性。 这需要一个Dictionary
,该属性可用作设置类的属性,例如:vidrec.WeakVideoSettings = new AVVideoSettings() { ... }.Dictionary;
NSObject
.ctor(IntPtr)
构造函数已从公共更改为受保护(以防止不当使用)。NSAction
已 替换为 标准 .NETAction
。 一些简单的(单参数)委托也已Action<T>
替换为 。
最后,请参阅 经典 v 统一 API 差异 ,在代码中查找 API 的更改。 搜索 此页面 有助于查找经典 API 及其已更新的内容。
注意
迁移后命名空间 MonoTouch.Dialog
保持不变。 如果代码使用 MonoTouch.Dialog,则应继续使用该命名空间 - 请勿更改为 MonoTouch.Dialog
Dialog
!
常见编译器错误
下面列出了常见错误的其他示例,以及解决方案:
错误 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.Foundation
Foundation
引用,但在某些情况下,需要手动更新这些引用。 以前包含 MonoTouch
的其他命名空间可能会出现类似的错误,例如 UIKit
。
错误 CS0266:无法将类型“double”隐式转换为“System.float”
修复:更改类型和强制转换为 nfloat
。 对于具有 64 位等效项的其他类型(例如 nint
,)也可能发生此错误
nfloat scale = (nfloat)Math.Min(rect.Width, rect.Height);
错误 CS0266:无法将类型“CoreGraphics.CGRect”隐式转换为“System.Drawing.RectangleF”。 存在显式转换(是否缺少强制转换?)
修复:将实例更改为RectangleF
CGRect
、SizeF
更改为CGSize
和PointF
更改为CGPoint
。 using 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
。 这通常发生在方法重写中,例如 onUITableViewSource
、RowsInSection
、NumberOfSections
、GetHeightForRow
TitleForHeader
、 GetViewForHeader
等。
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);
}
}