绑定OC类库

 

使用Objective-Sharpie绑定现有Objective-C类库

Objective-Sharpie:https://download.xamarin.com/objective-sharpie/ObjectiveSharp.pkg

 

本文提供一个手把手的练习,通过Xamarin.iOS绑定(Binding)到一个现有的Obj-C类库:InfColorPicker。这将涉及诸如编译一个静态的Obj-C类库,绑定这个类库,Xamarin.iOS应用程序使用这个绑定等问题。

 

概括

 

当工作在iOS时,你可能会碰到需要调用第三方Obj-C库的情况。在这些情况下,你可以通过Xamarin.iOS新建一个绑定项目(Binding Project) 绑定到第三方库,使得C#可以使用这个库。

 

本文使用一个开源Obj-C项目InfColorPicker做例子,一步一步演练如何新建一个绑定项目到InfColorPicker。InfColorPicker库的功能是提供可复用的视图控制器(View controller ),允许用户根据HSB来选择颜色,使颜色选择更方便。

 

 

 

我们将完成Xamarin.iOS调用这个Obj-C API的所有必要步骤:

●首先,我们用xcode创建一个Obj-C静态库。

●之后我们用Xamarin.iOS绑定这个静态库。

●接着使用工具 Objective Sharpie自动生成一些(是的,不是全部)必要的API定义,这能减少自己定义的工作量。

●最后,我们建立一个Xamarin.iOS项目来使用这个绑定。

 

这个示例将演示我们的c#代码使用强委托(strong delegate 译注1)调用InfColorPicker API。之后我们通过弱委托(weak delegate)来实现同样的功能。

 

 

 

 

要求

本文假设读者对Xcode和Obj-C有一定了解,并且已经读过Binding Objective-C这篇文档。

此外,下列的这些是必须的:

●Xcode 6 和 iOS --在苹果机上已经安装Xcode 6和最近的iOS API。

●Xcode Command Line Tools --在苹果机上已经安装当前Xcode版本匹配的Xcode命令行工具。(参阅下文的安装细节)

●Xamarin Studio 或 Visual Studio --在开发机已安装最新版的Xamarin Studio 或VisualStudio。Xamarin Studio (或Xamarin Build Host) 和一台苹果mac机是开发Xamarin应用必须的。(译注2)

●Objective Sharpie--当前版本的Objective Sharpie可以在这里下载

 

安装Xcode命令行工具Xcode Command Line Tools

如上所述,我们会使用到Xcode命令行工具(特别是make和lipo命令)。make命令是一个非常普遍的Unix命令,能执行makefile中的命令对项目程序和库进行编译。(译注3)

lipo是一个OS X的命令工具,能把适用于不同硬件架构的多个静态库文件(.a文件)打包到一个文件中。 

按照苹果文档Building from the Command Line with Xcode FAQ,在OS X10.9版本和更新的版本中,Xcode的首选项(默认)不再支持command-line tools的下载。

 

你可以使用下列的一些方法安装command-line tools:

●安装Xcode6 或新版本--在安装X6时,一些命令行工具已捆绑安装。 在OS X 10.9及之后,可以使用xcrun命令。

 

●使用终端(Terminal Application)-- 可以在终端中使用xcode-select --install命令安装:

   打开终端

   输入xcode-select --install 并回车

   会有安装向导,点击“安装”(Install)

 

 

   安装包会从苹果服务器下载并安装:

 

 

 

●从Apple Developers下载--Downloads for Apple Developers:

 

 

安装完命令行工具后,我们已经准备好继续进行这个演练。

 

 

演练

在这个演练里,我们会进行下列步骤:

●新建一个静态库--这步包括创建一个 Obj-C格式的静态库项目InfColorPicker ,输出一个.a扩展名的         静态库文件,该文件最终将被嵌入到.Net的类库中。

●新建一个Xamarin绑定项目-- 当完成一个静态库后,我们需要创建一个Xamarin的绑定项目(译注4)。这个绑定项目由之前我们创建的静态库及C#形式的元数据(meta-data)组成,C#的元数据描述了这些Obj-C API能被怎么使用。 这些元数据通常称为API 定义(API definitions)。我们将使用工具Objective Sharpie来帮助我们自动生成这些API定义。

●规范API定义--Objective Sharpie帮助我们做了很多工作,但在API能被使用前我们需要处理些变化--对自动生成的某些API做些调整。

●使用绑定的类库--最后,我们创建一个Xamarin应用来展示怎么使用之前创建好的绑定库。

 

现在我们已经知道了会涉及哪些步骤,让我们继续前进完成这些步骤。

 

创建一个静态类库

如果我们查看在Github上的 InfColorPicker项目:

 

我们可以看到项目中的3个文件夹:

• InfColorPicker - 这个文件夹包含项目的Objective-C 代码

• PickerSamplePad - 这个包含一个iPad的示例。

• PickerSamplePhone - 这个包含一个iPhone的示例。

 

让我们从GitHub下载InfColorPicker,并解压到本地的文件夹,用Xcode打开其中的PickerSamplePhone项目,我们能看到如下的项目结构:

 

 

那些InfColorPicker下的源代码文件是完整的底层方法(红框内的),可以直接复制到 新的项目中供使用。 在蓝框中的是示范的界面应用部分。因为这个下载项目没有直接提供静态类库,需要我们在自己的Xcode项目中编译一下,生成一个静态库。

 

让我们做以下这些:

1.启动Xcode

2.在文件菜单(File)下选择新建一个项目(New>Project) ...

 

 

 

3.选中Framework&Library,选择Cocoa Touch Static Library项,点击下一步按钮(Next):

 

 

 

4.输入项目名称InfColorPicker,点击下一步按钮(Next)

 

 

5.选择一个本地路径用来保存项目,点击OK按钮创建项目。

 

6.现在我们需要从下载来的 InfColorPicker项目中把源文件拷贝到我们自己的静态库项目中。

因为InfColorPicker.h文件已经默认生成,Xcode不允许我们覆盖它(不一定),我们打开Finder,定位到之前从github下载解压的项目中,拷贝InfColorPicker 下的所有文件并黏贴到我们新建的静态库项目中:

 

 

7.返回Xcode,在InfColorPicker文件夹上右击弹出菜单,选择 Add files to "InfColorPicker...":

 

 

 

8. 定位到我们刚刚拷贝到的文件,选择所有,点击Add按钮:

 

 

9.这些源文件将被添加到我们的项目里:

 

 

 

10.在Xcode中选中InfColorPicker.m文件(译注5),在代码编辑窗口注释掉最后2句(因为对应的头文件已经被覆盖,不需要实现)。

 

 

 

 

11.在Xcode方案选择(Scheme Selector)中,选择 InfColorPicker > iOS Device (确认下载的代码能在本机编译):

 

 

12.选中 InfColorPicker Target,然后选择Build Settings  选项:

 

 

13.滚动到Code Signing 部分,在Code Signing Identity下选中 Automatic > iOS Developer:

 

 

 

 

14.在Xcode菜单Product 下,选择 Build For > Running:

 

 

这个库项目将被编译,并且生成一个 InfColorPicker.a 文件。到这来我们已经很接近了,但还没有完成。我们刚生成的这个.a静态库适用于ARM架构的芯片,并且只能工作在iOS设备上。为了让库也能在iOS模拟器上运行(x86架构的硬件),我们需要建立一个完全版的(fat binary)的库。

 

 

 

创建一个完全版的类库

如上所述,刚建立的库文件只能适用于真正的iOS设备。为了也能在iOS模拟器上适用,我们需要创建一个完全版的类库。这有如下3个步骤的工作:

•创建一个ARM 7版本的静态库

•创建一个x86 版本的静态库

•使用lipo命令将2个库打包到一起

虽然这3步是相当简单的,但当Obj-C更新或是我们自己的代码更新时,必须要重复这些操作。如果你决定自动化这些操作,这个iOS绑定项目的支持和维护工作也能简单点。

 

有很多工具可以自动化这样的任务--一个shell脚本、rake、build、和make。当我们安装命令行工具时已经自动安装了make,所以在这个练习里我们会使用make。这里给出一段makefile命令,它可以生成适用于iOS设备与模拟器的InfColorPicker库并打包成一个:

 

[plain] view plain copy

print?

  1. XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild  
  2. PROJECT_ROOT=./InfColorPicker  
  3. PROJECT=$(PROJECT_ROOT)/InfColorPicker.xcodeproj  
  4. TARGET=InfColorPicker  
  5.   
  6. all: libInfColorPickerSDK.a  
  7.   
  8. libInfColorPicker-i386.a:  
  9.     $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build  
  10.     -mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $@  
  11.   
  12. libInfColorPicker-armv7.a:  
  13.     $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build  
  14.     -mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@  
  15.   
  16. libInfColorPickerSDK.a: libInfColorPicker-i386.a libInfColorPicker-armv7.a  
  17.     xcrun -sdk iphoneos lipo -create -output $@ $^  
  18.   
  19. clean:  
  20.     -rm -f *.a *.dll  

 

(译注:命令注意用tab键分隔)

 

在文本编辑器中输入makefile命令并保存,保存路径为我们之前创建的InfColorPicker Xcode静态库同一目录。(保存为makefil,不用扩展名,见下图) (译注6)

 

 

在mac机上打开终端,并定位到 InfColorPicker Xcode 静态库项目( Static Library)所在文件夹

输入make命令并回车,Makefile 将被执行:

 

 

运行make命令你会看到很多滚动信息,如果没什么错误,你会看到“ BUILD SUCCEEDED ”,并且在makefile文件的相同目录下看到生成的三个文件: 

libInfColorPicker-armv7.a,libInfColorPicker-i386.a , libInfColorPickerSDK.a

 

到这里,我们完成了整个练习的第一步:使用Xcode和命令行make\lipo生成一个静态库。让我们前进到下一步,使用Objective-Sharpie工具为我们自动生成API定义。

 

 

 

 

创建Xamarin.iOS绑定项目

在我们可以使用Objective-Sharpie自动处理前,我们需要先创建一个Xamarin.iOS绑定项目来容纳这些API定义(Objective-Sharpie会为我们自动生成定义)及C#的连接描述。

 

 

让我们做以下:

1.启动Xamarin Studio 

2.在“File”菜单下选择新建一个方案(New > Solution...):

 

 

3.在新建方案对话框,选择新建一个绑定项目(Library > iOS Binding Project):

 

 

4.点击下一步"Next"

5.输入InfColorPickerBinging作为绑定项目的名称,点击"Create"按钮创建方案:

 

 

方案被创建并默认已经包含2个文件:

 

 

•ApiDefinition.cs -- 这个文件是Obj-C API怎样被包装成C#的约定。

 

•StructsAndEnums.cs -- 这个文件里列出必要的结构和枚举声明。

 

 

我们之后将用到这2个文件。但首先,我们需要把InfColorPicker的静态库添加到绑定项目里。

 

在绑定项目中添加库

让我们做以下:

1.在刚创建的方案里右击InfColorPicker项目,在弹出菜单选择添加文件Add > Add Files...:

 

 

2.定位到 libInfColorPickerSDK.a文件,选中它并点击"Open"按钮

 

3.选择拷贝文件到文件夹(Copy the file to the directory),点击"OK"按钮

 

4.文件会被添加到项目里

 

当这个.a文件被添加到绑定项目,Xamarin.iOS会自动识别出这个Obj-C库,生成一个特定名称的文件libInfColorPickerSDK.linkwith.cs:

 

这个文件中的LinkWith属性告诉Xamarin该怎么处理这个刚添加的静态库。文件中内容是如下的一段代码:

[csharp] view plain copy

print?

  1. using ObjCRuntime;  
  2.   
  3. [assembly: LinkWith ("libInfColorPickerSDK.a", SmartLink = true, ForceLoad = true)]  

 

 

LinkWith属性可以定义绑定项目怎么处理静态库,同时可以设置些重要的链接标志 。

 

接下来的一件事情就是为 InfColorPicker项目建立API定义,为达成这个目标,我们将使用Objective Sharpie 自动生成具体的ApiDefinition.cs文件。

 

 

使用Objective Sharpie

Objective Sharpie是个命令行的工具(由Xamarin提供),能生成绑定到第三方Obj-C库时需要的接口定义。在这个小节,我们将使用Objective Sharpie生成InfColorPicker项目的初始 ApiDefinition.cs。

 

 

开始,让我们下载Objective Sharpie的安装包,运行安装程序,按照屏幕上的向导完成安装。

 

 

安装成功后,运行终端,输入下列命令可以查看这个工具提供的功能。

sharpie -help

 

如果执行了上面的命令,会有如下面的一些输出:

Europa:Resources kmullins$sharpie -help

usage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]

 

Options:

  -h, --helpShow detailed help

  -v, --versionShow version information

 

Available Tools:

 

  xcode    Get information about Xcode installations and available SDKs.

 

  bind     Create a Xamarin C#binding to Objective-C APIs

Europa:Resources kmullins$

 

我们会用到 ObjectiveSharpie的如下命令:

xcode --这个命令提供一些当前的Xcode、及iOS和MacAPIs的版本信息。当之后我们进行绑定工作时会用到这些信息。

bind --我们将使用这个命令来解析InfColorPicker 项目的头文件(.h文件)来初始化ApiDefinition.cs 和StructsAndEnums.cs 文件。

 

要获取 Objective Sharpie具体工具的帮助信息,可以输入工具的名称和 -help命令。 例如输入sharpie xcode -help会得到下列的信息:

Europa:Resources kmullins$sharpie xcode -help

usage: sharpie xcode [OPTIONS]+

 

Options:

  -h, --help                 Show detailed help

  -v, --verbose              Be verbose with output

      --sdks                 List all available Xcode SDKs. Pass -verbose for

                               more details.

Europa:Resources kmullins$

 

在我们处理绑定前,需要确认当前安装的一些SDK的信息。在终端输入以下命令sharpie xcode -sdks:

查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。

Europa:Resources kmullins$ sharpie xcode -sdks macosx10.10 macosx10.9 iphoneos8.1 iphonesimulator8.1 iphonesimulator7.1 Europa:Resources kmullins$

查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。

 

在终端输入下面的命令:

sharpie bind --output=InfColorPicker --namespace=InfColorPicker --sdk=iphoneos8.1 [full-path-to-project]/InfColorPicker/InfColorPicker/*.h

 

[full-path-to-project]是你机器上 InfColorPicker 项目的Xcode 项目文件(.xcodepro)所在的路径。这个例子中,我们使用了*.h的通配符来解析文件夹下的所有头文件。通常你可以不用这样处理,你可以使用一个顶级的头文件,并在里面正确引用所有相关的头文件,然后只要把这个顶级头文件指定给Objective Sharpie就可以。

终端上会有如下输出:

Europa:Resources kmullins$sharpie bind -output InfColorPicker -namespace InfColorPicker -sdk iphoneos8.1 /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h -unified

Compiler configuration:

    -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=8.1 -resource-dir /Library/Frameworks/ObjectiveSharpie.framework/Versions/1.1.1/clang-resources -arch armv7 -ObjC

 

[  0%] parsing /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h

In file included from /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h:60:

/Users/kmullins/Projects/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/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property

      attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]

/Users/kmullins/Projects/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/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property

      attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]

4 warnings generated.

[100%] parsing complete

[bind] InfColorPicker.cs

Europa:Resources kmullins$

 

 

同时,在我们的文件夹下,InfColorPicker.enums.cs 和InfColorPicker.cs文件已被创建 :

 

 

在Xamarin中打开这2个文件。复制InfColorPicker.cs 中的内容到ApiDefinition.cs ,即用InfColorPicker.cs中namespace开始的代码段替换掉现有的。(using引用声明不用替换)。

 

 

 

目前版本的 Objective Sharpie有时候会创建重复的接口定义,所以我们要找到第一个InfColorPickerControllerDelegate定义删除它。

 

 

InfColorPicker 会用到些CoreGraphics的类,需要添加CoreGraphics 的引用:

[csharp] view plain copy

print?

  1. using CoreGraphics;  

 

 

这个版本的Objective Sharpie翻译委托定义(Delegate)时有时会有问题,所以要用下面的的代码替换掉InfColorPickerControllerDelegate接口定义部分的[Protocol, Model] 行。

[csharp] view plain copy

print?

  1. [BaseType(typeof(NSObject))]  
  2. [Model]  

 

替换后的定义如下:

 

 

类似的,我们操作InfColorPicker.enums.cs文件。 除了using引用部分,复制所有内容到StructsAndEnums.cs:

 

 

这个版本的Objective Sharpie 还不能创建一个枚举类型的名称(醉了)。我们需要替换掉 <unamed-C-enum>,比如这里使用InfComponentIndex:

 

 

到这步,我们的绑定项目已经完成了。让我们编译一下看看有无错误。

 

 

 

 

使用绑定

我们现在已经有了一个绑定到InfColorPicker  Obj-C库的绑定库。让我们创建一个iPhone 的示例应用来使用这个绑定库。

 

 

1.创建Xamarin.iOS项目,新建一个叫InfColorPickerSample的Xamarin.iOS项目,如下截图:

 

 

 

 

 

2.添加对绑定项目的引用-使InfColorPickerSample 项目引用InfColorPickerBinding项目。

 

 

3.创建iPhone的UI-双击InfColorPickerSample项目的MainStoryboard.storyboard,在iOS设计界面添加一个叫 ChangeColorButton的按钮控件(Button),如下图:

 

 

 

4.添加 InfColorPickerView.xib --在InfColorPicker 的Obj-C库中包含(include)一个.xib文件,但Xamarin并未把它包含进绑定项目,这会导致我们运行示例程序时错误。解决办法是把这个.xib添加到我们的Xamarin项目。 右击我们的Xamarin项目,选择Add > Add Files,并定位到这个.xib文件。如下图:

 

 

5.在对话框中选择拷贝这个文件到项目

 

 

接下来,让我们快速浏览下Obj-C中的协议(Protocols  译注7) 是怎么被C#代码解析绑定的。

 

Protocols 和 Xamarin.iOS

在Obj-C中,一个协议(protocol)定义的方法(或message)可以在某些情况下被使用。概念上,Obj-C中的协议与C#中的接口(interface)是非常类似的,两者间一个主要的不同是,协议中可以有可选的方法--遵从该协议的类不一定非要实现这些方法。Obj-C中使用@optional 关键字来表明那些可选(optional)方法。关于protocol的更多信息可以访问Events, Protocols and Delegates。

 

InfColorPickerController中有一个这种协议,如下面的代码:

[objc] view plain copy

print?

  1. @protocol InfColorPickerControllerDelegate  
  2.   
  3. @optional  
  4.   
  5. - (void) colorPickerControllerDidFinish: (InfColorPickerController*) controller;  
  6. // This is only called when the color picker is presented modally.  
  7.   
  8. - (void) colorPickerControllerDidChangeColor: (InfColorPickerController*) controller;  
  9.   
  10. @end  

 

 

InfColorPickerController 实现了该协议,当用户选取了一个新的颜色,InfColorPickerController 处理完后将进行回调通知。Objective Sharpie将这个协议映射为如下的代码段:

[csharp] view plain copy

print?

  1. [BaseType(typeof(NSObject))]  
  2. [Model]  
  3. public partial interface InfColorPickerControllerDelegate {  
  4.   
  5.     [Export ("colorPickerControllerDidFinish:")]  
  6.     void ColorPickerControllerDidFinish (InfColorPickerController controller);  
  7.   
  8.     [Export ("colorPickerControllerDidChangeColor:")]  
  9.     void ColorPickerControllerDidChangeColor (InfColorPickerController controller);  
  10. }  

 

当绑定库(binding library)编译时,Xamarin会创建一个叫InfColorPickerControllerDelegate的抽象基类,该基类中用虚方法实现了这个接口。

 

 

有2种办法可以在Xamarin应用中实现这个接口:

•强委托(Strong Delegate)-- 使用强委托是指创建一个继承了InfColorPickerControllerDelegate的子类,并且实现(override)相应的方法。InfColorPickerController 将使用这个类的一个实例来与它的客户沟通。

•弱委托(Weak Delegate) -- 一个弱委托是种稍微不同技术方法,它是指在某个类中(比如InfColorPickerSampleViewController)创建一个公共方法并通过添加Export属性把该方法指定(exposing)给InfColorPickerDelegate协议。

 

强委托是可感知(可推断),类型安全,及封装良好的。出于这些原因,我们应该尽可能的使用强委托来代替弱委托。

 

在这个演练中,2种方法我们都会讨论到。 让我们从实现一个强委托开始,再完成一个弱委托。

 

实现一个强委托

用强委托来响应colorPickerControllerDidFinish的信息以完成我们的Xamarin应用。

 InfColorPickerControllerDelegate的子类--在这个步骤中我们为项目新添加一个类:ColorSelectedDelegate,编辑这个类如下:

[csharp] view plain copy

print?

  1. using InfColorPickerBinding;  
  2. using UIKit;  
  3.   
  4. namespace InfColorPickerSample  
  5. {  
  6.     public class ColorSelectedDelegate:InfColorPickerControllerDelegate  
  7.     {  
  8.         readonly UIViewController parent;  
  9.   
  10.         public ColorSelectedDelegate (UIViewController parent)  
  11.         {  
  12.             this.parent = parent;  
  13.         }  
  14.   
  15.         public override void ColorPickerControllerDidFinish (InfColorPickerController controller)  
  16.         {  
  17.             parent.View.BackgroundColor = controller.ResultColor;  
  18.             parent.DismissViewController (false, null);  
  19.         }  
  20.     }  
  21. }  

 

Xamarin会绑定Obj-C中的委托(delegate)到新建的抽象基类InfColorPickerControllerDelegate,我们的子类继承它并覆盖实现了ColorPickerControllerDidFinish方法,在方法中获取InfColorPickerController属性ResultColor的值。

 

新建ColorSelectedDelegate的实例-- 我们的事件处理程序需要一个实例,类型是之前我们创建的ColorSelectedDelegate。编辑类InfColorPickerSampleViewController ,添加一个如下的实例变量:

[csharp] view plain copy

print?

  1. ColorSelectedDelegate selector;  

 

初始化这个ColorSelectedDelegate变量--根据下面的代码,更新ViewController中的方法ViewDidLoad,以确保实例selector可用。

[csharp] view plain copy

print?

  1. public override void ViewDidLoad ()  
  2. {  
  3.     base.ViewDidLoad ();  
  4.     ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithStrongDelegate;  
  5.     selector = new ColorSelectedDelegate (this);  
  6. }  

 

实现HandleTouchUpInsideWithStrongDelegate方法--接下来我们需要实现事件处理--当用户点击ColorChangeButton按钮时。编辑ViewController,添加下来的方法:

[csharp] view plain copy

print?

  1. using InfColorPicker;  
  2. ...  
  3.   
  4. private void HandleTouchUpInsideWithStrongDelegate (object sender, EventArgs e)  
  5. {  
  6.     InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();  
  7.     picker.Delegate = selector;  
  8.     picker.PresentModallyOverViewController (this);  
  9. }  

 

我们首先通过静态方法得到 InfColorPickerController的实例, 再把我们定义的强委托赋给InfColorPickerController.Delegate,这个属性是Objective Sharpie为我们自动生成的。

最后我们调用PresentModallyOverViewController方法展示界面InfColorPickerSampleViewController.xib,用户得以选择颜色。

 

运行程序

到这里我们已经完成了所有功能代码,如果你运行程序,你可以设置背景色如下:

 

 

恭喜!你已经实现了在一个Xamarin应用中调用一个Obj-C类库。 接着,我们可以学习下弱委托的使用。

 

实现弱委托

作为子类继承及使用特定的委托以实现Obj-C协议方式的替代,Xamarin同样提供给你使用任何继承自NSObject的类的方法来实现Obj-C协议的方式--用Export属性装饰你的方法,并提供相应的选择(selectors)。当使用这种方式,你可以将你的类的一个实例赋给WeakDelegate属性来替换使用Delegate属性。弱委托为你提供了灵活性,将委托处理下降到不同的继承层次。让我们看看怎么在Xamarin应用中使用弱委托。

 

为TouchUpInside创建事件处理

让我们给设置背景色的按钮的TouchUpInside 事件添加事件处理。这个处理和之前章节创建的HandleTouchUpInsideWithStrongDelegate 有相同的职能,不过我们将使用弱委托来替换强委托。

编辑 ViewController类并添加如下的方法:

[csharp] view plain copy

print?

  1. private void HandleTouchUpInsideWithWeakDelegate (object sender, EventArgs e)  
  2. {  
  3.     InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();  
  4.     picker.WeakDelegate = this;  
  5.     picker.SourceColor = this.View.BackgroundColor;  
  6.     picker.PresentModallyOverViewController (this);  
  7. }  

 

更新ViewDidLoad--我们必须修改ViewDidLoad来使用我们新建的事件处理,修改ViewDidLoad如下的代码段:

[csharp] view plain copy

print?

  1. public override void ViewDidLoad ()  
  2. {  
  3.     base.ViewDidLoad ();  
  4.     ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithWeakDelegate;  
  5. }  

 

处理 colorPickerControllerDidFinish: Message--当ViewController处理完成,iOS会发送消息colorPickerControllerDidFinish:给弱委托。我们需要建一个C#方法来处理这个消息。为了完成这个,我们创建一个C#方法并用 Export属性修饰。编辑ViewController类并添加如下的方法:

[csharp] view plain copy

print?

  1. [Export("colorPickerControllerDidFinish:")]  
  2. public void ColorPickerControllerDidFinish (InfColorPickerController controller)  
  3. {  
  4.     View.BackgroundColor = controller.ResultColor;  
  5.     DismissViewController (false, null);  
  6. }  

 

运行这个程序,它和之前的功能是一样的,但使用弱委托替换了强委托。

到这里,你已经全部完成了整个演练。现在,你应该对怎么创建和使用一个Xamarin绑定项目有了一个了解。

 

摘要

本文演示了创建和使用一个Xamarin绑定项目的各个过程。首先我们讨论了怎样编译一个现有的Obj-C库到一个静态库。接着我们涉足了怎么创建一个Xamarin绑定项目,及怎么使用Objective Sharpie 生成Obj-C静态库的API定义。我们讨论了怎样更新和调整生成的API定义使它们能恰当的给外部调用。在Xamarin绑定项目完成后,我们转到在Xamarin应用项目中使用这个绑定,特别的,我们还讨论了强委托与弱委托的使用。

 

 

译注1:strong delegate在这里使用了C#中更熟悉的"委托"的叫法,但在iOS更强调的是引用的意思。weak delegate类似。

译注2:本文中的Xamarin.iOS是指在苹果机上的Xamarin环境,其实在 windows环境--Xamarin Studio或VS Xamarin中,你可以直接做类似的操作,如在VS里新建一个Xamarin binding project。

译注3:.Net程序员可能对makefile不熟悉,可以理解为一段脚本命令或一个批处理文件,其中会通过命令的方式调用IDE的编译器。在苹果机上可以通过文本软件创建,也有很多插件工具,或者,在终端直接输入命令:touch Makefile。更多信息请搜索makefil相关。

译注4:你同样可以在Windows环境创建绑定项目。

译注5:Obj-C中.h是头文件,.m文件是具体的实现内容。

译注6:可以直接指定具体的路径,也可以使用cd定位到文件夹,使用相对路径。

译注7:Obj-C中的Interface关键字是对类的声明,Protocols关键字 才更接近C#中的interface。

10-04 14:35