Как вызвать Objective-C NSExpression (формат: ....) из NativeScript? - PullRequest
0 голосов
/ 26 февраля 2019

Я работаю над расширением плагина NativeScript-Mapbox , чтобы включить возможность рендеринга кругов, размер которых изменяется при увеличении карты.Я работаю над примером на этой странице .

В iOS я столкнулся с проблемой, пытаясь перевести этот вызов NSExpression в NativeScript:

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

Это выглядитмне, что аналог NativeScript этому вызову, перечисленному в tns-platform-декларациях ... objc! Foundation.d.ts Определение выражения NSE:

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

Это правильный метод?

Если да, то как мне превратить [12: 2, 22: 180] в тип NSArray?

Не имея документации, я попытался создать массив массивов и передать его в:

new NSArray( {objects: myArray} );

но он ужасно падает с segfault.

Понятно, что я что-то упустил.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Чтобы вручную создать собственный объект iOS;это почти всегда:

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

Однако пара замечаний;

  1. Вы почти всегда хотите использовать NSMutableArray(), а не просто NSArray, поскольку NSArray является статическим;и Mutable означает, что вы можете изменить его.Так как вы создаете это в JS;Вы должны добавить значения к нему после его создания, чтобы Mutable был типом, который вам почти всегда нужен.
  2. В большинстве случаев вы можете использовать new NSMutableArray();;однако я сталкивался со случаями, когда new не работает должным образом против .alloc().init() на некоторых нативных объектах iOS, хотя 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, который мы передали. По умолчанию вызов любой функции iOS, которая ожидает, что NSArray автоматически преобразует любой массив JavaScript в NSArray для вас.Маршалинг большинства типов данных выполняется автоматически.
  4. Если функция iOS не имеет допустимых типов (например, тип vardef);или если функция имеет переменное число аргументов;тогда NativeScript может вообще не вызывать его, и поэтому при попытке вылетит с ошибкой.

Наконец, если у вас есть другие вопросы о том, как сделать JS для iOS (илиAndroid) в NativeScript;Я бы порекомендовал вам выполнить поиск по этому ключевому слову в 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})]));

Поскольку у массива нет определенного типа объекта, который может в него войти, безопаснее принудительно задать тип объекта, который мы помещаем вэто как NSDictionary, так как это то, что iOS будет ожидать.И просто чтобы убедиться, что то, что передается в expressWithFormatArgumentArray, является NSArray, мы оборачиваем JSArray, который мы создали, с помощью вызова NSArray.arrayWithArray().Вы, вероятно, можете уйти, просто делая [{}], но TS иногда ненавидит, не зная типов вещей.

0 голосов
/ 03 марта 2019

Хорошо, просто чтобы вернуться назад и закончить эту тему, я / наконец / выяснил, как заставить это работать без сбоев.

Для метода требуется массив с типом NSDictionary, и, по-видимому, определение типа NativeScript для NSDictionary неверно для этой проблемы и этой .

Таким образом, после нескольких дней проб и ошибок преобразование вызова 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 ([...]);

0 голосов
/ 27 февраля 2019

Объект swift (не target-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}]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...