【问题标题】:How to call Objective-C NSExpression( format: ....) from NativeScript?如何从 NativeScript 调用 Objective-C NSExpression(format: ....)?
【发布时间】:2019-02-26 17:10:38
【问题描述】:

我正在努力扩展NativeScript-Mapbox plugin 以包含渲染圆圈的功能,该圆圈会随着地图的缩放而调整大小。我正在使用example on this page

在 iOS 上,我在尝试将此 NSExpression 调用转换为 NativeScript 时遇到问题:

layer.circleRadius = [NSExpression expressionWithFormat: @"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
@{@12: @2, @22: @180}];

在我看来,tns-platform-declarations ..objc!Foundation.d.ts NSExpression 定义中列出的此调用的 NativeScript 类似物是:

static expressionWithFormatArgumentArray(expressionFormat: string, _arguments: NSArray<any>): NSExpression;

这是正确的方法吗?

如果是,如何将 [12: 2, 22: 180] 转为 NSArray 类型?

缺少文档,我尝试创建一个数组数组并将其传递给:

new NSArray( {objects: myArray} );

但它会因段错误而严重崩溃。

显然,我错过了一些东西。

【问题讨论】:

    标签: ios objective-c nativescript


    【解决方案1】:

    您正在处理的 swift(不是 Objective-c)对象不是数组,而是字典。

    import Swift
    print(type(of: [12: 2, 22: 180]))
    // Dictionary<Int, Int>
    

    它所期望的数组是你想要的所有格式替换参数的数组;在这种情况下,该数组的长度为1,并且只包含字典。你可以把它翻译成你的 NativeScript JavaScript/TypeScript:

    const expr = NSExpression.expressionWithFormatArgumentArray(
      "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
      [{12: 2, 22: 180}]);
    

    【讨论】:

    • 打字稿编译器给了我一个错误。 '{ 12: number; 类型的参数22: number;}[]' 不能分配给 NSArray 的类型。缺少属性计数。在条目中添加 count: 并不能修复编译错误。
    • 我升级了 Typescript 和核心模块,并开始编译。但是,它崩溃了,我不明白为什么。
    【解决方案2】:

    手动创建一个 Native iOS 对象;几乎总是这样:

    const x = NSArray.alloc().init();'
    or
    const y = new NSArray();
    

    但是有几个注意事项;

    1. 您几乎总是希望使用NSMutableArray() 而不仅仅是普通的NSArray,因为 NSArray 是静态的;而 Mutable 意味着你可以改变它。由于您是在 JS 中创建它;您必须在创建后为其添加值,因此 Mutable 是您几乎总是需要的类型。
    2. 大多数情况下可以使用new NSMutableArray();;但是,我遇到了 new 在某些本机 iOS 对象上与 .alloc().init() 无法正常工作的情况,即使 new 基本上是 .alloc().init() 的包装器。我建议你总是做 .alloc().init() 只是为了保持一致。;
    3. 如果iOS函数调用专门采用NSArray;然后你可以做这样的事情: const myNSArray = NSArray.arrayWithArray([1,2,3,4,5]);
      在这个例子中; myNSArray 现在是一个 NSArray 对象,[1,2,3,4,5] 最初是我们传入的一个 JS 数组对象。默认情况下,调用任何需要 NSArray 的 iOS 函数都会自动将任何 JavaScript 数组转换为 NSArray。大多数数据类型的封送处理会自动为您完成。
    4. 如果 iOS 函数没有有效类型(即 vardef 类型);或者如果函数具有可变数量的参数;那么 NativeScript 可能根本无法调用它,因此在您尝试时会崩溃并出现错误。

    最后,如果您对如何在 NativeScript 中将 JS 处理到 iOS(或 Android)有其他问题;我建议您在 http://searchcode.nativescript.rocks 上搜索该关键字,然后仔细阅读它找到的使用这些特定关键字的源代码。

    至于问题的NSExpression部分

    const expr = NSExpression.expressionWithFormatArgumentArray(
      "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
      NSArray.arrayWithArray([NSDictionary.dictionaryWithDictionary({12: 2, 22: 180})]));
    

    因为 Array 没有特定的对象类型可以放入其中,所以将我们放入其中的对象类型强制为 NSDictionary 会更安全,因为这是 iOS 所期望的。为了确保传递给expressWithFormatArgumentArray 的是一个NSArray,我们使用NSArray.arrayWithArray() 调用来包装我们创建的JSArray。您可能只需执行 [{}] 就可以逃脱惩罚,但 TS 有时讨厌不知道事物的类型。

    【讨论】:

    • 感谢您抽出宝贵时间如此彻底地回答我的问题。非常感谢。但是,我遇到了一个我不理解的编译时问题:mapbox.ios.ts:1427:26 - 错误 TS2345:'any[]' 类型的参数不可分配给'NSArray' 类型的参数。 “any[]”类型中缺少属性“count”。第1427章 NSArray.arrayWithArray([NSDictionary.dictionaryWithDictionary({12: 2, 22: 180})]));
    • 和 ``` mapbox.ios.ts:1427:66 - 错误 TS2345: 类型参数 '{ 12: number; 22:数字; }' 不可分配给“NSDictionary”类型的参数。对象字面量只能指定已知属性,而 '12' 不存在于类型 'NSDictionary' 中。第1427章```
    • 在此处查看问题线程中的讨论:github.com/NativeScript/NativeScript/issues/6971 即使该讨论中的链接示例 (github.com/NickIliev/NS-Issues-2019-I/blob/master/NativeScript/…) 也不起作用。我想知道我是否有可能的配置问题?
    • 我已验证以下 Objective-C 在测试应用程序中按预期工作: layer.circleRadius = [NSExpression expressionWithFormat: @"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential' , 1.75, %@)", @{@12: @2, @22: @180}];但是,相应的本机脚本编译但会导致崩溃: const expr = NSExpression.expressionWithFormatArgumentArray("mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)", [{12: 2, 22 : 180}]);
    【解决方案3】:

    好的,只是为了循环并完成这个线程,我 /finally/ 想出了如何让它在不崩溃的情况下工作。

    该方法需要一个包含 NSDictionary 类型的数组,并且根据 this issuethis one,NSDictionary 的 NativeScript 类型定义似乎不正确。

    所以经过几天的反复试验,转换了 Objective-C 调用:

    layer.circleRadius = [NSExpression expressionWithFormat: @"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
    @{@12: @2, @22: @180}];
    

    进入 TypeScript/NativeScript 是完全违反直觉的:

    let nsDict = new (NSDictionary as any)( [ 2, 180 ], [ 12, 22 ] );
    let nsArray = NSArray.arrayWithArray( [ nsDict ] );
    
    layer.circleRadius = NSExpression.expressionWithFormatArgumentArray(
      "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)", nsArray );
    

    这编译并工作。请注意,键位于值之后的单独数组中,而不是相反。

    如果您使用上面建议的 NSDictionary 方法,则会出现编译错误,因为显然输入不支持该表示法。

    升级到最新的 NativeScript 和核心模块确实允许它编译建议的 NSArray() [] 引用,但生成的代码会导致异常:,即:

    const expr = NSExpression.expressionWithFormatArgumentArray( "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)", [{12: 2, 22: 180}]);
    

    异常崩溃。

    据我所知,该数组未正确编组到 NSDictionary 实例中。同样使用 NSArray.arrayWithArray( [ ... ] );

    【讨论】:

      猜你喜欢
      • 2014-11-17
      • 2010-12-12
      • 2023-04-08
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      • 1970-01-01
      相关资源
      最近更新 更多