Как Parrot сравнивается с другими виртуальными машинами?

UPDATE: Если целью развертывания является iOS 11 или новее:

Начиная с iOS 11, UIKit будет анимировать cornerRadius, если вы обновите его внутри блока анимации. Просто установите layer.cornerRadius вашего представления в блок анимации UIView или (чтобы обрабатывать изменения ориентации интерфейса), установите его в layoutSubviews или viewDidLayoutSubviews.

ОРИГИНАЛ: Если цель развертывания старше чем iOS 11:

Итак, вы хотите это:

(Я включил Debug> Slow Animations, чтобы упростить гладкость чтобы увидеть.)

Боковое высказывание, не стесняйтесь пропустить этот абзац: это оказывается намного сложнее, чем должно быть, потому что SDK iOS не делает параметры (продолжительность, временная кривая) анимации авторотации, доступной удобным способом. Вы можете (я думаю) получить от них, переопределив -viewWillTransitionToSize:withTransitionCoordinator: на вашем контроллере просмотра, чтобы вызвать -animateAlongsideTransition:completion: на координаторе перехода, а в обратном вызове вы передадите transitionDuration и completionCurve из UIViewControllerTransitionCoordinatorContext. И тогда вам нужно передать эту информацию до вашего CircleView, который должен сохранить его (поскольку он еще не был изменен!), А позже, когда он получает layoutSubviews, он может использовать его для создания CABasicAnimation для cornerRadius с сохраненными параметрами анимации. И не случайно создавайте анимацию, когда это не анимированный размер ... End of side rant.

Ничего себе, это звучит как тонна работы, и вам нужно привлечь контроллер вида. Вот еще один подход, который полностью реализован внутри CircleView. Он работает сейчас (в iOS 9), но я не могу гарантировать, что он всегда будет работать в будущем, потому что он делает два предположения, которые теоретически могут быть ошибочными в будущем.

Вот такой подход: переопределить -actionForLayer:forKey: в CircleView, чтобы вернуть действие, которое при запуске устанавливает анимацию для cornerRadius.

Это два предположения:

  • bounds.origin и bounds.size получить отдельные анимации. (Это правда сейчас, но предположительно будущий iOS мог бы использовать одну анимацию для bounds. Было бы достаточно легко проверить анимацию bounds, если анимация bounds.size не найдена.)
  • Анимация bounds.size добавляется в слой до того, как Core Animation запросит действие cornerRadius.

Учитывая эти предположения, когда Core Animation запрашивает действие cornerRadius, мы можем получить анимацию bounds.size со слоя, скопировать ее и изменить копию для анимации cornerRadius. Копия имеет те же параметры анимации, что и оригинал (если мы не модифицируем их), поэтому она имеет правильную продолжительность и временную кривую.

Вот начало CircleView:

class CircleView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        updateCornerRadius()
    }

    private func updateCornerRadius() {
        layer.cornerRadius = min(bounds.width, bounds.height) / 2
    }

Обратите внимание, что границы представления задаются до того, как представление получает layoutSubviews, и поэтому перед обновлением cornerRadius. Вот почему анимация bounds.size установлена ​​перед запросом анимации cornerRadius.

Когда мы устанавливаем cornerRadius, Core Animation просит нас запустить CAAction:

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "cornerRadius" {
            if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
                let animation = boundsAnimation.copy() as! CABasicAnimation
                animation.keyPath = "cornerRadius"
                let action = Action()
                action.pendingAnimation = animation
                action.priorCornerRadius = layer.cornerRadius
                return action
            }
        }
        return super.action(for: layer, forKey: event)
    }

В код выше, если нас попросят выполнить действие для cornerRadius, мы будем искать CABasicAnimation на bounds.size. Если мы его найдем, мы скопируем его, изменим путь ключа к cornerRadius и сохраним его в пользовательском CAAction (класса Action, который я покажу ниже). Мы также сохраняем текущее значение свойства cornerRadius, потому что Core Animation вызывает actionForLayer:forKey: перед обновлением свойства.

После возвращения actionForLayer:forKey: Core Animation обновляет свойство cornerRadius этого слоя. Затем он запускает действие, отправив его runActionForKey:object:arguments:. Задача действия - установить любую анимацию. Вот пользовательский подкласс CAAction, который я вложил внутри CircleView:

    private class Action: NSObject, CAAction {
        var pendingAnimation: CABasicAnimation?
        var priorCornerRadius: CGFloat = 0
        public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
            if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
                if pendingAnimation.isAdditive {
                    pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
                    pendingAnimation.toValue = 0
                } else {
                    pendingAnimation.fromValue = priorCornerRadius
                    pendingAnimation.toValue = layer.cornerRadius
                }
                layer.add(pendingAnimation, forKey: "cornerRadius")
            }
        }
    }
} // end of CircleView

Метод runActionForKey:object:arguments: устанавливает свойства fromValue и toValue анимации, а затем добавляет анимация к слою. Есть осложнение: UIKit использует «аддитивные» анимации, потому что они работают лучше, если вы запускаете другую анимацию в свойстве, в то время как более ранняя анимация все еще работает. Поэтому наше действие проверяет это.

Если анимация является аддитивной, она устанавливает fromValue на разницу между старыми и новыми угловыми радиусами и устанавливает toValue на ноль. Поскольку свойство cornerRadius уровня уже обновлено к моменту запуска анимации, добавив, что fromValue в начале анимации делает его похожим на старый угловой радиус и добавляет toValue к нулю в конце анимации делает его похожим на новый угловой радиус.

Если анимация не является аддитивной (что не происходит, если UIKit создал анимацию, насколько я знаю), то она просто устанавливает значение fromValue и toValue.

Вот весь файл для вашего удобства:

import UIKit

class CircleView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        updateCornerRadius()
    }

    private func updateCornerRadius() {
        layer.cornerRadius = min(bounds.width, bounds.height) / 2
    }

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "cornerRadius" {
            if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
                let animation = boundsAnimation.copy() as! CABasicAnimation
                animation.keyPath = "cornerRadius"
                let action = Action()
                action.pendingAnimation = animation
                action.priorCornerRadius = layer.cornerRadius
                return action
            }
        }
        return super.action(for: layer, forKey: event)
    }

    private class Action: NSObject, CAAction {
        var pendingAnimation: CABasicAnimation?
        var priorCornerRadius: CGFloat = 0
        public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
            if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
                if pendingAnimation.isAdditive {
                    pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
                    pendingAnimation.toValue = 0
                } else {
                    pendingAnimation.fromValue = priorCornerRadius
                    pendingAnimation.toValue = layer.cornerRadius
                }
                layer.add(pendingAnimation, forKey: "cornerRadius")
            }
        }
    }
} // end of CircleView

Мой ответ был вдохновлен этим ответом Саймона .

28
задан Seki 11 June 2015 в 12:38
поделиться

4 ответа

Следующий ответ был написан в 2009 году. См. Также это обновление 2015 года от raiph .

Чтобы расширить @Reed и указать на некоторые особенности, коды операций Parrot находятся на гораздо более высоком уровне, чем у большинства виртуальных машин. Например, в то время как большинство машин хранят целые числа и числа с плавающей запятой, основными регистрами являются целые числа, числа, строки и файлы cookie Parrot Magic Cookies (PMC). Просто встроенные строки - это шаг вперед по сравнению с JVM.

Более интересен PMC, вроде как объектный тип JVM, но гораздо более взаимозаменяемый. PMC - это контейнер для всех других более сложных типов , которые вам нужны на реальном языке, таких как массивы, таблицы, деревья, итераторы, ввод-вывод и т. Д. PMC и большое количество встроенных для него операций означает меньше работы для лингвистического писателя. Parrot не уклоняется от беспорядочных, но необходимых элементов реализации языка.

Моя информация может быть устаревшей, но я считаю, что коды операций можно заменять, вы можете отправить виртуальную машину Parrot, которая содержит только коды операций, необходимые для вашего языка. Они также должны были быть унаследованными, если ваш язык хочет, чтобы их массивы работали немного иначе, чем стандартные массивы Parrot, вы можете создать его подкласс.

Наконец, Parrot может быть написан не только на ассемблере ( PASM ), но также язык немного более высокого уровня, Parrot Intermediate Presentation (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

Они также должны были быть унаследованными, если ваш язык хочет, чтобы их массивы работали немного иначе, чем стандартные массивы Parrot, вы можете создать его подкласс.

Наконец, Parrot может быть написан не только на ассемблере ( PASM ), но также язык немного более высокого уровня, Parrot Intermediate Presentation (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

Они также должны были быть унаследованными, если ваш язык хочет, чтобы их массивы работали немного иначе, чем стандартные массивы Parrot, вы можете создать его подкласс.

Наконец, Parrot может быть написан не только на ассемблере ( PASM ), но также язык немного более высокого уровня, Parrot Intermediate Presentation (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

если ваш язык хочет, чтобы их массивы работали немного иначе, чем стандартные массивы Parrot, вы можете создать его подкласс.

Наконец, Parrot может быть написан не только на ассемблере ( PASM ), но и на немного более высоком уровне. язык уровня, Промежуточное представление Parrot (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

если ваш язык хочет, чтобы их массивы работали немного иначе, чем стандартные массивы Parrot, вы можете создать его подкласс.

Наконец, Parrot может быть написан не только на ассемблере ( PASM ), но и на немного более высоком уровне. язык уровня, Промежуточное представление Parrot (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

Parrot может быть написан не только на ассемблере ( PASM ), но и на языке немного более высокого уровня, Parrot Intermediate Presentation (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

Parrot может быть написан не только на ассемблере ( PASM ), но и на языке немного более высокого уровня, Parrot Intermediate Presentation (PIR) . В PIR есть циклы, подпрограммы, локализованные переменные и некоторые базовые математические операции и операции сравнения, все основы, которые люди ожидают от языка программирования, не выходя слишком далеко от металла.

В общем, Parrot очень дружелюбен к разработчикам языков ( он написан ими и для них), которые хотят разработать язык и оставить как можно большую часть реализации кому-то другому.

34
ответ дан 28 November 2019 в 02:45
поделиться

Вы можете прочитать многое из этого на странице Parrot VM Intro .

Основное преимущество Parrot перед JVM или CLR заключается в том, что он разработан для поддержки динамических языков в первую очередь и потенциально обеспечить лучшую поддержку и производительность для динамически типизированных языков. И JVM, и CLR больше ориентированы на поддержку языков со статической типизацией, и многие проектные решения показывают это.

15
ответ дан 28 November 2019 в 02:45
поделиться

Еще одна вещь, которая отличает Parrot от большинства виртуальных машин (безусловно, отличается от JVM), - это то, что это регистровая машина, а не стековая. Но я думаю, люди еще долго будут спорить, можно ли это назвать преимуществом или недостатком.

5
ответ дан 28 November 2019 в 02:45
поделиться

Я недостаточно знаю JVM и CLR, но мои советы:

  • динамические языки (замыкания, полиморфные скаляры, продолжения, со-рутины) поддерживают (скорость)
  • диспетчеризацию динамических методов,
  • функции первого класса,
  • первоклассные продолжения,
  • параметры (опционально, по желанию, по названию, . .),
  • регистр
  • имеет HLL-совместимость, предоставляемую на уровне сборки
  • диапазон платформ

Обновление: Вероятно, это не имеет значения, так как в настоящее время JVM является одним из бэкэндов Rakudo Perl 6. См. Rakudo Perl 6 на JVM (Perl 6 Advent calendar 2013, Day 3).

.
5
ответ дан 28 November 2019 в 02:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: