Создание приложений OS X с помощью JavaScript

Original author: Tyler Gaw
  • Translation
Недавно в OS X Yosemite была представлена возможность использования JavaScript для автоматизации. Это открывает возможность получать доступ к нативным* фреймворкам OS X из JavaScript. Я тут покопался в этом новом мире и собрал несколько примеров. В этом посте я объясню основы и шаг за шагом покажу процесс создания небольшого приложения.
На WWDC 2014 проходила сессия по автоматизации с помощью JavaScript. На ней рассказывали, что вы теперь можете использовать JavaScript для автоматизации приложений вместо AppleScript. Это само по себе увлекательная новость. Возможность автоматизировать повторяющиеся операции с помощью AppleScript существует уже довольно давно. Писать на AppleScript — не самое приятное занятие, так что использовать вместо него знакомый синтаксис было бы очень хорошо.
Во время этой сессии докладчик рассказал о мосте с Objective-C. Вот здесь начинается самое интересное. Мост позволяет вам импортировать любой Objective-C фреймоврк в JS приложение. Например, если вы хотите написать GUI используя стандартные элементы управления OS X, вам нужно импортировать Cocoa:
ObjC.import("Cocoa"); 

Фрейморк Foundation делает именно то, что предполагает его название. Он позволяет собирать блоки для приложений OS X. В нем есть огромный набор классов и протоколов. NSArray, NSURL, NSUserNotification, и т.д. Может быть, вы и не знакомы со всеми ними, но их названия подсказывают, для чего они служат. Из-за своей крайней важности, фреймворк доступен по умолчанию, без необходимости импорта в новое приложение.
Насколько я могу судить, вы можете сделать на JavaScript все то же самое, что и на Objective-C или Swift.

Пример


Внимание: для работы этого примера вам необходима Yosemite Developer Preview 7+
Лучший способ чему-то научиться — это просто взять и попробовать что-то сделать. Я собираюсь показать вам процесс создания небольшого приложения, которое может показывать изображения с компьютера.
Вы можете скачать полный пример из моего репозитория.

Скрин приложения, которое я собираюсь написать.

В приложении будет: окно, текстовый блок, поле ввода и кнопка. Ну, или по названиям классов: NSWindow, NSTextField, NSTextField и NSButton.
Клик по кнопке «Выбор файла» откроет NSOpenPanel для выбора файла. Мы настроим панель таким образом, что она не даст пользователю выбирать файлы с расширением, отличным от .jpg, .png и .gif.
После выбора изображения мы покажем его в окне. Окно будет подгонять свой размер под ширину и высоту изображения плюс высота элементов управления. Мы так же укажем минимальные размеры окна чтобы элементы управления у нас не пропали.

Настройка проекта


Откройте приложение Apple Script Editor в Applictions > Utilities. Это не самый лучший редактор из тех, что я пробовал, но сейчас он необходим. Там есть ряд необходимых фич для сборки приложения OS X на JS. Не уверен, что там происходит под капотом, но он умеет компилировать и запускать ваши скрипты как приложения. Он так же создает дополнительные нужные вещи, как например файл Info.plist. Мне кажется, есть возможность заставить и другие редакторы делать то же, но я еще не разбирался с этим.
Создайте новый документ через File > New или cmd + n. Первое, что нам надо сделать — сохранить документ как приложение. Сохраните его через File > Save или cmd + s. Не спешите разу сохранять. Там есть две настройки, которые необходимы для того, чтобы запускать проект как приложение.

Script Editor с необходимыми настройками

Измените формат на «Application» и отметьте галочку «Не закрывать»**
Важное замечание: эти настройки можно поменять: откройте меню File и удерживайте кнопку option. Это откроет пункт «Save As...». В диалоге сохранения можно вносить изменения в настройки. Но лучше сделать это сразу при создании проекта.
Если вы не отметите флажок «Не закрывать», то ваше приложение откроется, а затем сразу же закроется. В интернете почти нет документации по этому функционалу. Я узнал об этом только после того, как несколько часов бился лбом в клавиатуру.

Давайте уже что-то сделаем!


Добавьте в ваш скрипт следующие строчки и запустите все через Script > Run Application или cmd + r.
ObjC.import("Cocoa");  
$.NSLog("Hi everybody!"); 

Почти ничего не произошло. Единственные видимые изменения — в строке меню и доке. В строке меню появилось название приложения и пункты File и Edit. Можете видеть, что приложение запущено, так как его иконка теперь в доке.
Где же строчка «Hi everybody!»? И что за знак доллара, jQuery? Закройте приложение через File > Quit или cmd + q и давайте выясним, где же произошло это NSLog.
Откройте консоль: Applications > Utilities > Console. Каждое приложение может писать что-то в консоль. Она не намного отличается от Developer Tools в Chrome, Safari или Firefox. Основное отличие в том, что вы производите отладку приложений вместо сайтов.
В ней много сообщений. Отфильтруйте ее написав «applet» в строке поиска в правом верхнем углу. Вернитесь в Script Editor и запустите приложение снова через opt + cmd + r.

Видели!? Сообщение «Hi everybody!» должно появиться в консоли. Если его там нет, закройте ваше приложение и запустите снова. Я много раз забывал его закрыть и код не запускался.

Что насчет знака доллара?


Знак доллара — это и есть ваш доступ к мосту в Objective-C. Каждый раз когда вам необходимо получить доступ к классу или константе Objective-C, вам нужно использовать $.foo или ObjC.foo. Позже я расскажу и про другие способы использовать $.
Приложение «Консоль» и NSLog — незаменимые вещи, вы всегда будете использовать их для отладки. Чтобы узнать, как логгировать что-то кроме строк, изучите мой пример с NSLog.

Создаем окно


Давайте сделаем что-нибудь, с чем можно взаимодействовать. Допишите ваш код:
ObjC.import("Cocoa");  
 
var styleMask = $.NSTitledWindowMask | $.NSClosableWindowMask | $.NSMiniaturizableWindowMask; 
var windowHeight = 85; 
var windowWidth = 600;  
var ctrlsHeight = 80;  
var minWidth = 400; 
var minHeight = 340; 
var window = $.NSWindow.alloc.initWithContentRectStyleMaskBackingDefer( $.NSMakeRect(0, 0, windowWidth, windowHeight), styleMask, $.NSBackingStoreBuffered, false );  
 
window.center; 
window.title = "Choose and Display Image"; 
window.makeKeyAndOrderFront(window); 

Затем запустите приложение. opt + cmd + r. Вот теперь поговорим! Небольшим количеством кода мы сделали приложение, которое можно двигать, сворачивать и закрывать.

Простое окно NSWindow, созданное с помощью JS

Если вам, как и мне, никогда не приходилось создавать приложения с Objective-C или Cocoa, все это может выглядеть слегка бредово. Мне такими показалалсь длина названий методов. Мне нравятся описательные имена, но Cocoa заходит уж слишком далеко.
Тем не менее, это JavaScript. Код выглядит так, как будто вы пишете сайт.
Что же происходит в первых строчках, где мы устанавливаем значение styleMask? Маски стилей используются для настройки окон. Каждая опция говорит о том, что она добавляет; заголовок, кнопку закрытия, кнопку сворачивания. Эти опции — константы. Используйте побитовое или ("|") для отделения одной настройки от другой.
Опций много. Можете прочитать о них всех в документации. Попробуйте добавить NSResizableWindowMask и посмотреть, что произойдет.
Вам нужно запомнить несколько любопытных вещей касательно синтаксиса. $.NSWindow.alloc вызывает метод alloc объекта NSWindow. Обратите внимание, что после вызова метода нет скобок. В JavaScript таким образом получается доступ к свойствам, а не методам. Как так выходит? В JS для OS X скобки разрешено применять только в том случае, если вы передаете параметры. Попытка использовать скобки без аргументов приведет к runtime error. Если что-то идет не так, как задумано, смотрите в консоль на наличие ошибок.
Вот пример супер-длинного названия метода:
initWithContentRectStyleMaskBackingDefer 

В документации к NSWindow этот метод выглядит несколько иначе:
initWithContentRect:styleMask:backing:defer:
В Objective-C такие окна создаются следующим способом:
NSWindow* window [[NSWindow alloc] 
    initWithContentRect: NSMakeRect(0, 0, windowWidth, windowHeight) 
    styleMask: styleMask, 
    backing: NSBackingStoreBuffered 
    defer: NO
];

Обратите внимание на двоеточия (":") в исходном описании метода. Для использования Objective-C метода в JS нужно их убрать и заменить следующую букву на заглавную. Квадратные скобки ("[]") — это вызов метода класса/объекта. [NSWindow alloc] вызывает метод alloc класса NSWindow. В JS это эквивалентно NSWindow.alloc, плюс, если надо, скобки.
Думаю, оставшаяся часть кода достаточно проста. Я пропущу подробное ее описание. Чтобы разобраться с тем, чт происходит дальше, вам понадобится много времени и придется много читать документацию, но вы справитесь. Если у вас показывается окно, то уже здорово. Давайте сделаем что-нибудь еще.

Добавляем элементы управления


Нам нужны метка (label), текстовое поле и кнопка. Мы будем использовать NSTextField и NSButton. Обновите свой код и снова запустите приложение.
ObjC.import("Cocoa"); 
var styleMask = $.NSTitledWindowMask | $.NSClosableWindowMask | $.NSMiniaturizableWindowMask; 
var windowHeight = 85; 
var windowWidth = 600; 
var ctrlsHeight = 80; 
var minWidth = 400; 
var minHeight = 340; 
var window = $.NSWindow.alloc.initWithContentRectStyleMaskBackingDefer( $.NSMakeRect(0, 0, windowWidth, windowHeight), styleMask, $.NSBackingStoreBuffered, false ); 
var textFieldLabel = $.NSTextField.alloc.initWithFrame($.NSMakeRect(25, (windowHeight - 40), 200, 24)); 

textFieldLabel.stringValue = "Image: (jpg, png, or gif)"; 
textFieldLabel.drawsBackground = false; 
textFieldLabel.editable = false; 
textFieldLabel.bezeled = false; 
textFieldLabel.selectable = true; 

var textField = $.NSTextField.alloc.initWithFrame($.NSMakeRect(25, (windowHeight - 60), 205, 24));
textField.editable = false; 
var btn = $.NSButton.alloc.initWithFrame($.NSMakeRect(230, (windowHeight - 62), 150, 25)); 
btn.title = "Choose an Image..."; 
btn.bezelStyle = $.NSRoundedBezelStyle; 
btn.buttonType = $.NSMomentaryLightButton; 
window.contentView.addSubview(textFieldLabel); 
window.contentView.addSubview(textField); 
window.contentView.addSubview(btn); 
window.center; 
window.title = "Choose and Display Image"; 
window.makeKeyAndOrderFront(window); 

Если все прошло успешно, то теперь у вас есть окно с элементами управления. В поле ничего нельзя ввести, а кнопка ничего не делает, но постойте-ка, мы уже продвигаемся.

Элементы управления в окне

Что мы здесь сделали? textFieldLabel и textField похожи между собой. Они оба экземпляры NSTextField. Мы создали их так же, как создавали окно. Когда вы видите initWithFrame и NSMakeRect, то скорее всего, здесь создается элемент UI. NSMakeRect делает то, что вынесено в его название. Он создает прямоугольник с указанными координатами и размерами; (x, y, width, height). В результате создается то, что в Objective-C называется «структура». В JS эквивалентом может быть объект, хэш или, возможно, словарь. Пары ключ-значение.
После создания текстовых полей установим каждому горстку свойств чтобы получить желаемый результат. В Cocoa нет ничего похожего на html элемент label. Значит, сделаем свой отключив фон и возможность редактирования.
Мы установим текстовое поле программно, попутно отключив редактирование. Если бы нам это не было нужно, то мы бы обошлись одной строкой.
Для создания кнопки мы используем NSButton. Так же, как и в случае с текстовым полем, нам необходима структура. Выделим два свойства: bezelStyle и buttonType. Значения обоих — константы. Эти свойства определяют, как элемент будет нарисован и какие стили он будет иметь. См. документацию по NSButton чтобы узнать, что еще можно сделать с кнопкой. У меня так же есть пример, где показаны различные стили и типы кнопок в действии.
Последнее из нового, что мы здесь делаем — это добавление элементов в окно с помощью addSubView. В первый раз я попытался сделать это используя
window.addSubview(theView)

На других стандартных представлениях, которые вы создаете с помощью NSView, это сработает, но не с экземплярами NSWindow. Не уверен почему, но в окна элементы нужно добавлять в contentView. В документации сказано: «Самый верхний доступный объект NSView в иерархии окна». У меня сработало.

Заставляем кнопку работать


Нажатие на кнопку «Выбрать изображение», должно приводить к открытию панели, отображающей файлы на компьютере. Перед этим давайте разогреемся, добавив вывод сообщения в консоль при нажатии на кнопку.
В JS к элементам привязываются обработчики событий для обработки нажатий. Objective-C использует несколько другую концепцию. Он использует то, что называется «передача сообщений»***. То есть вы передаете объекту сообщение, содержащее название метода. Объект должен иметь информацию о том, что ему делать, когда он получает такое сообщение. Может, это и не самое точное описание, но я понимаю так.
Первое — нужно установить target и action у кнопки. Target — это объект, которому нужно послать сообщение, содержащееся в action. Если сейчас не понятно, двигайтесь дальше, вы все поймете, когда увидите код. Обновите часть скрипта, где производится настройка кнопки:
... 
btn.target = appDelegate; 
btn.action = "btnClickHandler"; 
...

appDelegate и btnClickHandler пока не существуют. Надо их сделать. В следующем коде важен порядок. Я добавил комментарии, чтобы показать, где новый код.
ObjC.import("Cocoa"); 
// Вот здесь 
ObjC.registerSubclass({ 
    name: "AppDelegate",
    methods: { 
        "btnClickHandler": { 
            types: ["void", ["id"]], implementation: function (sender) { $.NSLog("Clicked!"); 
            } 
        } 
    } 
}); 
var appDelegate = $.AppDelegate.alloc.init; 
// Вот до сюда 
// Далее то, что уже было 
var textFieldLabel = $.NSTextField.alloc.initWithFrame($.NSMakeRect(25, (windowHeight - 40), 200, 24)); 
textFieldLabel.stringValue = "Image: (jpg, png, or gif)"; 
... 

Запустите приложение, нажмите на кнопку и смотрите в консоль. Видите сообщение «Clicked!», когда нажимаете на кнопку? Если да, то это же просто отпад, да? Если нет, то проверьте код и ошибки в консоли.

Наследование


А что за ObjC.registerSubclass? Наследование — это способ создать новый класс, который наследуется от другого класса Objective-C. Лирическое отступление: здесь есть вероятность использования мной неправильной терминологии. Боритесь со мной. registerSubclass принимает один аргумент: JS объект, содержащий свойства нового объекта. Свойства могут быть: name, superclass, protocols, properties и methods. Я на 100% не уверен, что это исчерпывающий список, но так это описано в release notes.
Это все хорошо и прекрасно, но что мы здесь сделали? Так как мы не указали superclass, наследуемся от NSObject. Это базовый класс для большинства классов Objective-C. Свойство name позволит нам в будущем обращаться к новому классу через $ или ObjC.
$.AppDelegate.alloc.init; создает экземпляр нашего класса AppDelegate. Еще раз, обратите внимание, что скобки у вызовов методов alloc и init не используются, так как мы не передаем им аргументов.

Методы наследника


Метод создается тем, что вы назначаете ему любое строковое имя. Например, btnClickHandler. Передайте ему объект со свойствами types и implementation. Официальной документации по поводу того, что должен содержать массив types я не нашел. Методом проб и ошибок я понял, что он выглядит как-то так:
["return type", ["arg 1 type", "arg 2 type",...]] 

btnClickHandler ничего не возвращает, так что первый элемент будет void. Он принимает один параметр, объект, отправляющий сообщение. В нашем случае NSButton, который мы назвали btn. Полный список типов доступен здесь.
implementation это обычная функция. В ней вы пишете JavaScript. У вас есть все тот же доступ к $, как и вне объекта. Так же вам доступны переменные, объявленные вне функции.

Небольшое замечание об использовании протоколов


Вы можете наследовать подклассы от протоколов Cocoa, но есть подводные камни. Мне удалось выяснить, что если использовать массив protocols, ваш скрипт просто вылетит без ошибок. Я написал пример и объяснение, так что если хотите с ними работать — почитайте.

Выбор и показ изображений


Мы готовы открыть панель, выбрать изображение и показать его. Обновите код функции
 btnClickHandler: 
... 
implementation: 
    function (sender) { 
        var panel = $.NSOpenPanel.openPanel; 
        panel.title = "Choose an Image"; 
        var allowedTypes = ["jpg", "png", "gif"]; 
        // NOTE: Мост из массива JS в массив NSArray
        panel.allowedFileTypes = $(allowedTypes); 
            if (panel.runModal == $.NSOKButton) { 
                // NOTE: panel.URLs - это NSArray, а не JS array 
                var imagePath = panel.URLs.objectAtIndex(0).path; 
                textField.stringValue = imagePath; 
                var img = $.NSImage.alloc.initByReferencingFile(imagePath); 
                var imgView = $.NSImageView.alloc.initWithFrame( $.NSMakeRect(0, windowHeight, img.size.width, img.size.height)); 
                window.setFrameDisplay( $.NSMakeRect( 0, 0, (img.size.width > minWidth) ? img.size.width : minWidth, ((img.size.height > minHeight) ? img.size.height : minHeight) + ctrlsHeight ), true ); 
                imgView.setImage(img); 
                window.contentView.addSubview(imgView); window.center; 
                } 
            } 

Во-первых, мы создаем экземпляр NSOpenPanel. Вы видели панели в действии, если когда-либо выбирали файл или выбирали куда этот файл сохранить.
Все, что нам от приложения нужно — это показывать изображения. Свойство allowedFileTypes позволяет нам определить, какие типы файлов панель сможет выбирать. Оно принимает значение типа NSArray. Мы создаем JS массив с допустимыми типами, но нужно еще его сконвертировать в NSArray. Это делается так: $(allowdTypes). Это еще один способ использования моста. Мы используем этот способ для того, чтобы перевести JS значение в Objective-C. Обратная операция производится так: $(ObjCThing).js.
Открываем панель с помощью panel.runModal. Выполнение кода при этом приостанавливается. Если нажать Cancel или Open, панель вернет значение. Если нажата кнопка Open, вернется константа $.NSOKButton.
Следующее замечание по поводу panel.URLs очень важно. В JS доступ к значениям массива произодится так: array[0]. Из-за того, что URLs имеет тип NSArray, использовать квадратные скобки нельзя. Вместо этого нужно использовать метод objectAtIndex. Результат будет тот же.
После получения URL изображения можно создавать новый экземпляр NSImage. Так как создание изображения по URL файла — широко распространенный подход, для этого есть удобный метод:
initByReferencingFile
NSImageView создается тем же самым способом, который мы использовали для создания других UI элементов. imgView управляет показом изображения.
Нам необходимо подгонять размер окна под ширину и высоту изображения, при этом не выходя за нижние пределы высоты/ширины. Для изменения размера окна используем setFrameDisplay.
Таким образом, мы установили изображение для imageView и добавили его в окно. Так как его ширина и высота изменились, окно нужно центрировать.
И вот такое наше маленькое приложение. Вперед, откройте парочку файлов. И да, анимированные гифки тоже будут работать, так что не забудьте про них.

Пикантные новости


До сих пор вы запускали приложение по opt + cmd + r. Но обычное приложение вы запускаете двойным щелчком по иконке.

Дважды кликните по иконке, чтобы запустить приложение

Иконку можно изменить заменой /Contents/Resources/applet.icns. Чтобы получить доступ к ресурсам приложения, щелкните правой кнопкой по иконке и выберите пункт «Show Package Contents».

Почему меня это так взбудоражило


Потому что я думаю здесь большой потенциал. Вот почему. Когда Yosemite выйдет, кто угодно сможет сесть и написать нативное приложение. И смогут они это сделать используя один из наиболее распространенных языков программирования. Им не придется ничего скачивать или устанавливать. Даже XCode не нужно будет устанавливать, если не хочется. Порог вхождения будет сильно понижен. Это невероятно.
Я знаю, что разработка приложений для OS X — это гораздо более глубокий процесс, нежели написание скрипта на коленке. У меня нет иллюзий по поводу того, что JavaScript станет де-факто стандартом для начала разработки под Mac. Я считаю, что это поможет разработчикам писать небольшие приложения, которые сделают разработку проще для себя и других людей. У вас есть в команде человек, которому сложно работать с командной строкой? Напишите для него GUI по-быстрому. Нужно способ быстро, в визуальном режиме создавать или изменять конфиги? Сделайте для этого маленькое приложение.
Эти возможности есть и в других языках. В Python и Ruby есть доступ к тем же самым нативным API и люди делают приложения с их использованием. Однако использование для этого JavaScript — это другое. Это переворачивает все с ног на голову. Как будто DIY-принципы web-разработки стучатся в дверь разработки под Десктоп. Apple оставили дверь незапертой, я захожу.

Примечания переводчика:
* — native, слово уже становится общеупотребимым, например, для отличия HTML5-приложений и традиционных
** — Stay open after run handler, не уверен как именно называется настройка в русскоязычной версии Script Editor
*** — message passing
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 35

    +4
    Интересно, а какой стандарт js используется? В смысле есть ли генераторы, классы / модули, рожь пшеница вот это все из ES6?
      +1
      Тоже интересно, что доступно. Хотя думаю они просто используют JSC из Safari в комплекте.
        0
        Угу, так и есть, я попробовал и генераторы с классами оно не умеет.
      +4
      С учетом того, что сейчас и Windows позволяет писать на JS, можно ждать очередной кросплатформенный фреймоворк для создания десктопных приложений без использования связки node.js + webkit.
        0
        Было бы отлично
        0
        Если автор знает про Swift, зачем ему нужны эти костыли с JS? Их же по коду даже не сразу отличишь.
          +1
          Это вопрос не к автору а к Apple, которые почему-то сделали автоматизацию через Apple Script и JS но не дали возможность писать скрипты на Swift.
            0
            Речь же про написание приложений. Для доступа к нативным фреймворкам в Swift не нужны никакие скрипты и автоматизация.
          0
          Что за странное у вас оформление OS X?
            +9
            Это стандартный внешний вид в OS X Yosemite
              –4
              Это бета какая-то? А как она оказалась на вашей машине? Это возможно вообще? В любом случае, это кошмар. Они лишили меня объёмных кнопок на iOS, теперь хотят сделать то же самое на OS X. А вернуть назад никак :(
                0
                поработал месяц — стало нормально и теперь очень даже нравится.
                  0
                  > Как она оказалась на вашей машине? Это возможно вообще?

                  Раньше пререлизные версии софта Apple раздавала тем, у кого была лицензия разработчика, теперь вот для OS X действует специальная программа раннего доступа. Вот, посмотрите: appleseed.apple.com/sp/betaprogram

                  А по поводу внешнего вида могу сказать, что некрасивым оно кажется первые полчаса, а потом обратно на Mavericks уже не хочется.
                    0
                    В первых бетах по-началу у меня вообще было местами ощущение, что в KDE попал :) но потом, вроде, привык
                      0
                      А стабильные у них беты? Я вот помню обновился на maverics у меня отваливаться wi-fi начал.
                        +2
                        Да релиз уже через неделю вроде как обещают, подождите на бету переползать :)
                          0
                          Пользуюсь с самой первой беты. Периодически вылезали косяки с оформлением, но оно и понятно, бета всё-таки. Но их вроде все исправили. Из проблем, с которыми столкнулся — homebrew считал, что 10.10 — недостаточно большая цифра и говорил, что нужна версия 10.8 (или 10.7, не помню) и новее :)

                          Ещё после последнего обновления макбук, когда просыпается, не видит wi-fi есть если она скрытая, приходися включать и выключать wi-fi в настройках.

                          Других проблем пока не встречал.
                        +3
                        Мне до сих пор хочется назад на iOS 6. Интерфейс стал менее тактильным что ли. В смысле, перестал вызывать тактильные ассоциации.
                  +2
                  Хм, не сочтите за еретика, но код на Objective C и написание того же самого в XCode выглядит как-то поприятнее :). Хотя начинание лично мне очень нравится.
                    +3
                    Ох и странно это выглядит. Пишешь то на JS, но синтаксис Objective-C всё равно знать нужно. По сути это и есть синтаксис Objective-C. Получается какая-то каша.

                    Вместо
                    var textFieldLabel = $.NSTextField.alloc.initWithFrame($.NSMakeRect(25, (windowHeight - 40), 200, 24));

                    как мне кажется, лучше уж сразу на Objective-C писать
                    NSTextField *textFieldLabel = [[NSTextField alloc] initWithFrame(NSMakeRect(25, (windowHeight - 40), 200, 24))];


                    Уж если ты знаешь синтаксис Objective-C — то какой смысл писать на JS?

                    Единственное, для чего это может пригодиться, так это для создания какого-то фреймворка, который избавит от написания различных alloc, initWithFrame, NSMakeRect и прочих штук из Objective-C, непонятных для JS-разработчика. Вот тогда было бы круто, какой-то более простой инструментарий без вникания в синтаксис другого языка.
                      +1
                      В JS доступ к значениям массива произодится так: array[0]. Из-за того, что URLs имеет тип NSArray, использовать квадратные скобки нельзя. Вместо этого нужно использовать метод objectAtIndex.

                      Прям подтверждение моих слов. Вроде бы массив, но как массив в JS ты его использовать не можешь, нужно использовать все те же методы, что и в Objective-C. Ну и какой тогда смысл? :)
                        0
                        Если что — скептически отношусь только к идее такого написания приложения для OS X, за перевод статьи всё равно спасибо, поставил плюс :)
                        0
                        режим зануды включен

                        NSTextField *textFieldLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(25, windowHeight — 40, 200, 24)];

                        режим зануды выключен
                          0
                          Ох и странно это выглядит. Пишешь то на JS, но синтаксис Objective-C всё равно знать нужно. По сути это и есть синтаксис Objective-C. Получается какая-то каша.

                          Блин, у меня такое же чувство возникает, когда при написании кода на Swift я сталкиваюсь с UIKit'ом
                          0
                          Возник вопрос: какие преимущества данный подход имеет перед node-webkit?
                            0
                            Не нужно устанавливать ничего дополнительно, все из коробки
                              0
                              Ну тот же нод-вебкит позволяет собрать приложение, которое пойдёт так же из коробки, не требуя дополнительных телодвижений, минус, разумеется, очевиден — размер приложения, но зато наличествует кроссплатформенность.
                                0
                                Без xcode можно писать приложения? К примеру пришёл к другу, он попросил помочь что-то автоматизировать, не скачивать же ради этого xcode — открыл редактор, накидал код и запустил. Так можно?
                                  0
                                  Да, именно эту мысль автор изложил в выводе как один из пунктов, почему идея JS в OS X показалась крутой
                                0
                                Я не использовал, но разве не тем, что используются нативные элементы?
                                  0
                                  Впринципе соглашусь. Будет выглядеть более нативно, по скорости особо различий быть не должно.
                                0
                                А как подобные приложения подписываются и попадают в АппСтор Мака?
                                  0
                                  Насколько я помню правила — никак…
                                    +1
                                    А почему нет? На нод + вебкит приложения проходят?
                                      0
                                      Хм… а пример можете показать? Я не находил, емнип

                                Only users with full accounts can post comments. Log in, please.