返回博客主页
← 所有文章

如何在 NativeScript 中使用 Swift 或 Objective-C 代理

2023 年 5 月 22 日 — 作者:Nandee Tjihero

这篇博文将向您展示如何在 NativeScript 中创建和使用 iOS 代理。

来自 iOS 中的代理是什么?

代理是任何在发生有趣事件时应收到通知的对象。这个“有趣事件”的含义取决于上下文:例如,表格视图的代理会在用户点击行时收到通知,而导航控制器的代理会在用户在视图控制器之间移动时收到通知。

颜色选择器示例

让我们看看 UIColorPickerViewController,它提供了一种呈现用户可以选择的颜色选择的方法。当控制器检测到用户颜色选择时,它需要一种方法来通知您的应用程序所选的颜色。它通过代理来实现这一点。Apple 为不同的目的提供了不同的协议。对于 UIColorPickerViewController,它提供了 UIColorPickerViewControllerDelegate 协议。

使用此代理,让我们更新 NativeScript 中 StackLayoutbackgroundColor。为了从选择器接收选定的颜色,我们遵守 UIColorPickerViewControllerDelegate 协议。

我们始终可以通过两个阶段来进行控制器/代理设置。

注意:请确保您理解 NativeScript 中代理的简短但重要的最佳实践用法:代理,代理,代理!!

阶段 1:创建代理实现

创建一个代理实现类,我们将其称为 ColorPickerDelegateImpl,它 extends NSObject 并遵守(也称为 implements)代理协议 UIColorPickerViewControllerDelegate

@NativeClass()
class ColorPickerDelegateImpl
  extends NSObject
  implements UIColorPickerViewControllerDelegate {

    // informs NativeScript to wire up the protocol
    static ObjCProtocols = [UIColorPickerViewControllerDelegate];

    // best practice to have an owner weak reference
    owner: WeakRef<HelloWorldModel>;

    // common pattern with statically initializing an implementation
    static initWithOwner(owner: WeakRef<HelloWorldModel>) {
      const delegate = <ColorPickerDelegateImpl>ColorPickerDelegateImpl.new();
      delegate.owner = owner;
      return delegate;
    }

    // implement delegate methods here...
}

理解重点

  • 在使用 NativeScript 创建平台类实现时,我们总是用 @NativeClass() 装饰它们。@NativeClass() 装饰器确保与 NativeScript 运行时相符,您可以了解更多信息 这里
  • 我们最常扩展 NSObject,因为它提供了我们的实现所需的所有通用基本 iOS 行为,并且因为我们的代理只是一个协议,也称为 interface,它无法扩展(只能由实现遵守)。
  • static ObjCProtocols 数组可以包含我们希望实现使用的任意数量的协议,并通知 NativeScript 代表我们连接指定的协议。
  • 一个常见的最佳实践是允许代理实现拥有一个所有者弱引用。所有者是从这个代理进行通信的类。您可以了解更多信息 弱引用
  • 有很多方法可以实例化一个实现类,但使用 static initWithOwner(owner: WeakRef<HelloWorldModel>) 模式已经变得很普遍,因为它允许您在不干扰平台(super)构造函数的情况下,将其他引用作为附加方法参数传入。值得注意的是,ColorPickerDelegateImpl.new() 是 NativeScript 为所有平台类添加的一个方便的简单构造函数,它避免了您可能希望稍后处理的特定 init 参数,并返回一个 NSObject,这就是为什么我们只需将其转换为我们的类型 <ColorPickerDelegateImpl> 的原因。

当您希望在代理及其所有者之间传递事件和数据时,所有者弱引用就会发挥作用。让我们通过实现 UIColorPickerViewControllerDelegate 提供的几种方法来做到这一点。

import { Color } from '@nativescript/core';

@NativeClass()
class ColorPickerDelegateImpl
  extends NSObject
  implements UIColorPickerViewControllerDelegate
{
  // ...

  // all delegate methods come from Apple documentation:
  // https://developer.apple.com/documentation/uikit/uicolorpickerviewcontrollerdelegate#3635512

  colorPickerViewControllerDidFinish(
    viewController: UIColorPickerViewController
  ) {
    // did close/finish event
    this.owner?.deref()
      .changeColor(Color.fromIosColor(viewController.selectedColor));
  }

  colorPickerViewControllerDidSelectColorContinuously(
    viewController: UIColorPickerViewController,
    color: UIColor,
    continuously: boolean
  ) {
    // selecting colors event
  }
}

阶段 2:使用代理

创建将使用您的代理的控制器

const picker = UIColorPickerViewController.alloc().init();

初始化我们上面创建的代理实现,同时将其分配给实例属性,如 最佳实践 中所述。

this.colorDelegate = ColorPickerDelegateImpl.initWithOwner(
  new WeakRef(this)
);

设置需要它的控制器的 delegate 属性

picker.delegete = this.colorDelegate;

观察平台如何运作。

立即通过 StackBlitz 在您的手中体验

惊喜连连 🎉

想要更多更简洁的代理示例?这里还有另一个从头开始实现表格视图代理以对列表视图进行排序的示例!

鸣谢