高级概念
iOS 子类化和协议一致性
扩展 iOS 类
以下示例演示如何扩展 UIViewController
const MyViewController = UIViewController.extend(
{
// Override an existing method from the base class.
// We will obtain the method signature from the protocol.
viewDidLoad: function () {
// Call super using the prototype:
UIViewController.prototype.viewDidLoad.apply(this, arguments)
// or the super property:
this.super.viewDidLoad()
// Add UI to the view here...
},
shouldAutorotate: function () {
return false
},
// You can override existing properties
get modalInPopover() {
return this.super.modalInPopover
},
set modalInPopover(x) {
this.super.modalInPopover = x
},
// Additional JavaScript instance methods or properties that are not accessible from Objective-C code.
myMethod: function () {},
get myProperty() {
return true
},
set myProperty(x) {},
},
{
name: 'MyViewController',
}
)
NativeScript 运行时添加了 .extend
API 作为一种选项,它在任何平台原生类上都可用,这些类接受一个包含该类平台实现 (classMembers
) 的对象,以及一个可选的第二个参数对象,该对象定义了下面解释的 nativeSignature
。
您还可以将 @NativeClass()
装饰器与标准类 extends
一起使用,这可能感觉更自然一些。
在创建扩展其他类的自定义平台原生类时,始终确保其名称对系统上的其他类唯一,以避免类名冲突。
@NativeClass()
class JSObject extends NSObject implements NSCoding {
public encodeWithCoder(aCoder) {
/* ... */
}
public initWithCoder(aDecoder) {
/* ... */
}
public 'selectorWithX:andY:'(x, y) {
/* ... */
}
// An array of protocols to be implemented by the native class
public static ObjCProtocols = [NSCoding]
// A selector will be exposed so it can be called from native.
public static ObjCExposedMethods = {
'selectorWithX:andY:': {
returns: interop.types.void,
params: [interop.types.id, interop.types.id],
},
}
}
注意
不应该有 TypeScript 构造函数,因为它不会被执行。而是覆盖其中一个 init
方法。
公开方法示例
如上所示,在 NativeScript 中扩展原生类采用以下形式
const <DerivedClass> = <BaseClass>.extend(classMembers, nativeSignature);
classMembers
对象可以包含三种类型的函数
- 基类覆盖,
- 原生可见函数,以及
- 纯 JavaScript 函数
纯 JavaScript 函数无法被原生库访问。如果要使函数对原生库可见并可调用,请将 nativeSignature
参数传递给 extend
,并使用所需的附加元数据提供有关函数签名的必要信息。
nativeSignature
参数是可选的,并具有以下属性
name
- 可选,包含派生类名称的字符串protocols
- 可选,包含已实现协议的数组exposedMethods
- 可选,包含函数名称
和原生函数签名
对象的字典
原生函数签名
对象有两个属性
returns
- 必需,类型
对象params
- 必需,类型
对象数组
通常,类型对象是 运行时类型
之一
- 一个构造函数,用于识别 Objective-C 类
interop.types
对象中的基本类型- 在极少数情况下,它可以是使用 interop API 描述的引用类型、结构类型等。
以下示例说明如何将纯 JavaScript 函数公开给 Objective-C API
const MyViewController = UIViewController.extend(
{
viewDidLoad: function () {
// ...
const aboutButton = UIButton.buttonWithType(
UIButtonType.UIButtonTypeRoundedRect
)
// Pass this target and the aboutTap selector for touch up callback.
aboutButton.addTargetActionForControlEvents(
this,
'aboutTap',
UIControlEvents.UIControlEventTouchUpInside
)
// ...
},
// The aboutTap is a JavaScript method that will be accessible from Objective-C.
aboutTap: function (sender) {
const alertWindow = new UIAlertView()
alertWindow.title = 'About'
alertWindow.addButtonWithTitle('OK')
alertWindow.show()
},
},
{
name: 'MyViewController',
exposedMethods: {
// Declare the signature of the aboutTap. We can not infer it, since it is not inherited from base class or protocol.
aboutTap: { returns: interop.types.void, params: [UIControl] },
},
}
)
覆盖初始化器
初始化器应始终返回对对象本身的引用,如果无法初始化,则应返回 null
。这就是为什么在尝试使用 self
之前需要检查它是否存在的原因。
const MyObject = NSObject.extend({
init: function () {
const self = this.super.init()
if (self) {
// The base class initialized successfully
console.log('Initialized')
}
return self
},
})
符合 Objective-C/Swift 协议
以下示例符合 UIApplicationDelegate
协议
const MyAppDelegate = UIResponder.extend(
{
// Implement a method from UIApplicationDelegate.
// We will obtain the method signature from the protocol.
applicationDidFinishLaunchingWithOptions: function (
application,
launchOptions
) {
this._window = new UIWindow(UIScreen.mainScreen.bounds)
this._window.rootViewController = MyViewController.alloc().init()
this._window.makeKeyAndVisible()
return true
},
},
{
// The name for the registered Objective-C class.
name: 'MyAppDelegate',
// Declare that the native Objective-C class will implement the UIApplicationDelegate Objective-C protocol.
protocols: [UIApplicationDelegate],
}
)
让我们看看如何通过为 Tesseract-OCR-iOS API 设置一个委托来在 TypeScript 中声明委托
interface G8TesseractDelegate extends NSObjectProtocol {
preprocessedImageForTesseractSourceImage?(
tesseract: G8Tesseract,
sourceImage: UIImage
): UIImage
progressImageRecognitionForTesseract?(tesseract: G8Tesseract): void
shouldCancelImageRecognitionForTesseract?(tesseract: G8Tesseract): boolean
}
实现委托
// native delegates often always extend NSObject
// when in doubt, extend NSObject
@NativeClass()
class G8TesseractDelegateImpl extends NSObject implements G8TesseractDelegate {
static ObjCProtocols = [G8TesseractDelegate] // define our native protocols
static new(): G8TesseractDelegateImpl {
return <G8TesseractDelegateImpl>super.new() // calls new() on the NSObject
}
preprocessedImageForTesseractSourceImage(
tesseract: G8Tesseract,
sourceImage: UIImage
): UIImage {
console.info('preprocessedImageForTesseractSourceImage')
return sourceImage
}
progressImageRecognitionForTesseract(tesseract: G8Tesseract) {
console.info('progressImageRecognitionForTesseract')
}
shouldCancelImageRecognitionForTesseract(tesseract: G8Tesseract): boolean {
console.info('shouldCancelImageRecognitionForTesseract')
return false
}
}
使用符合 G8TesseractDelegate
协议的类
let delegate: G8TesseractDelegateImpl
function image2text(image: UIImage): string {
let tess: G8Tesseract = G8Tesseract.new()
// The `tess.delegate` property is weak and won't be retained by the Objective-C runtime so you should manually keep the delegate JS object alive as long the tessaract instance is alive
delegate = G8TesseractDelegateImpl.new()
tess.delegate = delegate
tess.image = image
let results: boolean = tess.recognize()
if (results == true) {
return tess.recognizedText
} else {
return 'ERROR'
}
}
限制
- 您不应该扩展已扩展的类
- 您不能覆盖静态函数或属性
- 您不能公开静态函数或属性