пятница, мая 30, 2008

Хороший стиль Flex-программирования. ASDoc

Немного о комментировании/документировании в стиле ASDoc: ASDoc.

ASDoc

Комментирование свойств

Документируйте только первую функцию пары установщик/получатель (get/set). Пример объявления и документирования свойства:

/**
* @private
* The backing variable for the property.
*/
private var _someProp:Foo;

/**
* Place all comments for the property with the getter which is defined first.
* Comments should cover both get and set behavior as appropriate.
*/
public function get someProp():Foo
{
...
}

/**
* @private
*/
public function set someProp(value:Foo):void
{
...
}

Комментарии ASDoc применимы к тегам метаданных так же как и к другим элементам класса. Поэтому важно, чтобы комментарий относился к правильному элементу. Например, если свойство обозначено тегом Bindable, комментарий должен располагаться непосредственно перед функцией получателя (get), а не над метатегом Bindable:

можно:


[Bindable("somePropChanged")]
/**
* Comments for someProp
*/
public function get someProp():Foo

нельзя:
/**
* Comments for someProp
*/
[Bindable("somePropChanged")]

public function get someProp():Foo

Про документирование ASDoc можно посмотреть подробнее здесь.

PS: Ввиду уродского движка редактирования текста Blogger, местами поехали все пробелы в статье Хороший стиль Flex-программирования. Форматирование. Поэтому, лучше не надеяться на примеры кода, а читать текст.

Заключение

Цикл переводных статей про хороший стиль Flex-программирования еще не закончен. Через некоторое время я вернусь к этим статьям и, возможно, те правила, которые были отмечены автором как TBD будут опубликованы. На сегодня мы имеем достаточно информации, чтобы улучшить свой код. Будем надеяться, что с выходом Flash Player 10, новых SDK и т.п., правила сильно не изменятся.

Хороший стиль Flex-программирования. Форматирование

Здесь речь пойдет о том, как лучше оформлять файлы Flex-фреймворка. Статья Formatting.

Форматирование

Длина строки

Используйте перенос на следующую строку, если длина строки превышает 80 символов. Это дает следующие преимущества:

  • Разработчикам, у которых экран имеет малое разрешение, не потребуется горизонтально прокручивать длинные строки текста.
  • Можно комфортно сравнивать две версии программного кода, расположив два окна встык.
  • При показе кода на экране проектора, можно установить большой размер шрифта, и при этом не потребуется горизонтально прокручивать текст.
  • При печати, исходный код не будет обрезаться, или непредсказуемо переноситься.

Отступы

Используйте отступы в 4 пробела. Настройте редактор так, чтобы вместо символа табуляции вставлялись символы пробелов. Это необходимо для того, чтобы в код выглядел без искажений в программах с другой системой формирования отступов. Например Notepad отображает отступы в 8 символов.

Разделительные блоки

Код необходимо разбивать на разделы, а полученные разделы - озаглавливать. Для этого используйте большой и малый разделители.

Большой разделитель выглядит следующим образом:

//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------

Блок большого разделителя начинается с 4-го символа строки и заканчивается на 80-м. Текст начинается с 8-го символа.

Малый разделитель выглядит следующим образом:

//----------------------------------
// visible
//----------------------------------

Блок малого разделителя начинается с 4-го символа строки и заканчивается на 40-м. Текст начинается с 8-го символа.

Необходимо вставлять одну пустую строку до и одну после каждого разделителя.

Разделение блоков объявления

Используйте одну пустую строку для разделения блоков объявления констант, переменных, функций:
/**
* @private
* Holds something.
*/
var a:Number;
/**
* @private
*/
var b:Number

Метаданные

можно: Inspectable[a="1", b="2"]
нельзя: Inspectable[a=1 b=2]

Индексирование массивов

Не ставьте пробелы:
- до или после левой квадратной скобки,
- перед правой квадратной скобкой.

можно: a[0]
нельзя: a [ 0 ]

Расстановка запятых

После запятой, оставляйте один пробел. Это правило распространяется на список аргументов, элементы массива, свойства объекта.

Массивы

Ставьте один пробел:
- после левой квадратной скобки,
- перед правой квадратной скобкой,
- после каждой запятой.

можно: [ 1, 2, 3 ]
нельзя: [1, 2, 3] [1,2,3]

Исключение составляет только пустой массив:
можно: []
нельзя: [ ]

Если строка инициализации массива слишком длинна, разбивайте ее на несколько строк с выравниванием квадратных скобок:

static var numberNames:Array /* of String */ =
[
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine"
];

Объекты

Ставьте один пробел:
- после левой фигурной скобки,
- перед правой фигурной скобкой,
- после каждого двоеточия,
- после каждой запятой.

можно: { a: 1, b: 2, c: 3 }
нельзя: {a: 1, b: 2, c: 3} {a:1, b:2, c:3} {a:1,b:2,c:3}

Исключение составляет только пустой массив:
можно: {}
нельзя: { }

Если строка инициализации объекта слишком длинна, разбивайте ее на несколько строк с выравниванием квадратных скобок:

private static var TextStyleMap:Object =
{
color: true,
fontFamily: true,
fontSize: true,
fontStyle: true,
fontWeight: true,
leading: true,
marginLeft: true,
marginRight: true,
textAlign: true,
textDecoration: true,
textIndent: true
};

Функции

Пример форматирования:

var f:Function;
f = function():void
{
doSomething();
};

Объявление типов

Не ставьте пробелы до и после двоеточия, которое разделяет имя переменной, параметра, или функцию от типа.

можно: var n:Number;
нельзя:
var n : Number;
var n: Number;

можно: function f(n:Number):void
нельзя:
function f(n : Number) : void
function f(n: Number): void

Использование пробелов в операторах

Ставьте пробелы до и после оператора присваивания:
можно: a = 1;
нельзя: a=1;

Ставьте пробелы до и после инфиксного оператора:
можно: a + b * c
нельзя: a+b*c

Ставьте пробелы до и после оператора сравнения:
можно: a == b
нельзя: a==b

Не ставьте пробел между префиксным оператором и операндом:
можно: !o
нельзя: ! o

Не ставьте пробел между операндом и постфиксным оператором:
можно: i++
нельзя: i ++

Операторы

Начинайте каждый оператор с новой строки. Это дает возможность установить контрольную точку (breakpoint) на любой из операторов.
можно:
a = 1;
b = 2;
c = 3;
нельзя:
a = 1; b = 2; c = 3;

Всегда выравнивайте фигурные скобки блоков операторов:
можно:

function f():void
{
var n:int = numChildren;
for (var i:int = 0; i < n; i++)
{
if ()
{
x = horizontalGap * i;
y = verticalGap * i;
}
}
}

Нельзя:

function f():void {
var n:int = numChildren;
for (var i:int = 0; i < n; i++) {
if () {
x = horizontalGap * i;
y = verticalGap * i;
}
}
}

Объявление функций

Ставьте один пробел после каждой запятой. Никогда не ставьте пробелов после левой скобки и перед правой скобкой:
можно: f(a, b)
нельзя: f(a,b) f( a, b )

Если список параметров переносится на другую строку, перенесенные строки должны иметь отступ на уровне первого параметра после левой скобки. Можно располагать несколько параметров на одной строке, только если они умещаются. В ином случае, располагайте каждый параметр на отдельной строке. Если четный параметр не умещается, перенесите первый параметр на следующую строку с отступом на уровне начала имени функции.


public function foo(parameter1:Number, parameter2:String,
parameter3:Boolean):void

public function foo(parameter1:Number,
parameter2:String,
parameter3:Boolean):void

public function aVeryLongFunctionName(
parameter1:Number, parameter2:String,
parameter3:Boolean):void

Вызов функций

Ставьте один пробел после каждой запятой. Никогда не ставьте пробелов после левой скобки и перед правой скобкой:
можно: f(a, b)
нельзя: f(a,b) f( a, b )

Оператор if

Ставьте пробел между ключевым словом if и левой скобкой. Никогда не ставьте пробелов после левой скобки и перед правой скобкой:
можно: if (a < b)
нельзя:
if(a < b)
if( a < b )
if ( a < b )

Оператор for

Ставьте пробел между ключевым словом for и левой скобкой. Никогда не ставьте пробелов после левой скобки и перед правой скобкой:
можно: for (var i:int = 0; i < n; i++)
нельзя:
for(var i:int = 0; i < n; i++)
for( var i:int = 0; i < n; i++ )
for ( var i:int = 0; i < n; i++ )

Если описание цикла переносится на другую строку, перенесенные строки должны иметь отступ на уровне первого символа после левой скобки:


for (var aLongLoopVariableName:int = aLongInitialExpression;
aLongLoopVariableName < aLongUpperLimit;
aLongLoopVariableName++)

Оператор switch

Ставьте пробел между ключевым словом switch и левой скобкой. Никогда не ставьте пробелов после левой скобки и перед правой скобкой:
можно: switch (n)
нельзя:
switch(n)
switch( n )
switch ( n )

Комментарий

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

В основном, всё логично и выполнимо. Последний FlashDevelop успешно реализует эти правила в своем автокомплите. Теперь стало ясно, почему они так резко изменили политику расстановки фигурных скобок функций, а именно, перенос левой фигурной скобки на следующую строку. Честно говоря, я с этим переносом намучался, поскольку при переходе на стиль форматирования FlashDevelop, я специально переучивался оставлять левую скобку на строке с определением функции. А тут вдруг огорошили... И опять возвращаться к прежнему формату.

Ну всё. Следующий проект начинаю правильно форматировать.

Кстати, о проектах, которые сделаны в старом (не по правилам) формате. Часто приходится к ним возвращаться, дорабатывать, улучшать. Но уже трудно работать по-старому. Как тут быть? На переформатирование времени тратить не хочется. Где взять такой реформатер??!

Пока для себя я держу правило - работать в контексте стиля программирования дорабатываемого кода. Мой это код или чужой - всё равно следовать правилам текущего документа.
Если проект важный, в итоге будет выделено время на рефакторинг и всё само собой встанет на места.
Если проект чужой - он, вероятно, попадет обратно к автору, а тот лучше поймет что ему делать со своими или не своими (но похожими :) ) каракулями.

Остался маленький "хвостик" про ASDoc, который мы сейчас и разберем.

четверг, мая 29, 2008

Хороший стиль Flex-программирования. Структура файла

Сегодня мы поговорим о том, как правильно организовать структуру файла Flex-фреймворка. Оригинальный текст: File Organization. По этой теме информации пока не много - большая ее часть в разработке.

Структура файла

Порядок организации файла следующий:

  • Блок Copyright
  • Объявление пакета package
  • Список объявлений import
  • Объявление use namespace
  • Метаданные класса
  • Объявление класса class
  • Инициализация класса extends
  • Список объявлений implements
  • Подключение файла Version.as
  • Список констант класса
  • Список "mix-ins"
  • Ресурсы, используемые классом
  • Переменные класса (static)
  • Свойства класса (static)
  • Методы класса (static)
  • Конструктор
  • Переменные
  • Переопределяемые свойства
  • Свойства
  • Переопределяемые методы
  • Методы
  • Переопределяемые обработчики событий
  • Обработчики событий
  • Вспомогательные классы, не входящие в пакет

Блок Copyright

Вставляйте в каждый .as-файл фреймворка блок copyright. Текст open-source copyright '2008 можно посмотреть здесь: Блок Copyright. Ширина блока - 80 символов.

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

Группируйте метаданные в разделы, в следующем порядке:

  • Events
  • Styles
  • Effects
  • Excluded APIs
  • Other Metadata

Вставляйте малый разделитель перед каждым разделом. (О большом и малом разделителях будет написано в следующей главе "Форматирование").

В каждом разделе располагайте метаданные в алфавитном порядке по имени name="...", а в разделе Other Metadata - по имени тега.

Код примера можно посмотреть здесь: Организация метаданных класса.

Подключение файла Version.as

В каждый класс необходимо подключать файл Version.as, содержащий объявление константы с номером версии static const VERSION:String:
include "../core/Version.as";

Список констант класса

Здесь объявляются статические константы static const.
ActionScript 3 не позволяет объявлять константы типов Array и Object. Такие константы необходимо объявлять как static var, но помещать в этот раздел, поскольку по своей сути они являются константами.

Список "mix-ins"

Здесь объявляются любые статические переменные типа Function, которые принимают ссылки на методы, но не объявляются в качестве методов. (Понятие mix-in я раскрыл так, как смог понять - возможно я ошибаюсь).

Свойства класса (static)

Здесь объявляются статические установщики и получатели (getter/setter) класса. Располагайте их в алфавитном порядке по имени свойства. Для каждого, используйте подзаголовок с именем свойства. Объявляйте сначала получатель, затем установщик.

Методы класса (static)

Здесь размещаются статические функции static function.

Переопределяемые свойства

Здесь объявляются переопределяемые нестатические установщики и получатели (getter/setter) класса. Располагайте их в алфавитном порядке по имени свойства. Для каждого, используйте подзаголовок с именем свойства. Объявляйте сначала получатель, затем установщик.

Свойства

Здесь объявляются новые нестатические установщики и получатели (getter/setter) класса. Располагайте их в алфавитном порядке по имени свойства. Для каждого, используйте подзаголовок с именем свойства. Объявляйте сначала получатель, затем установщик.

Переопределяемые методы

Здесь размещаются переопределяемые нестатические функции.

Методы

Здесь размещаются новые нестатические функции.

Переопределяемые обработчики событий

Здесь размещаются переопределяемые обработчики событий.

Обработчики событий

Здесь размещаются новые обработчики событий.

Комментарий

Я изменил порядок следования пунктов, так как они в оригинале расположены в абсурдном порядке:

  • Подключение файла Version.as
  • Список объявлений implements
  • Инициализация класса extends

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

Для оформления класса "в релиз" это конечно важно, но для личного пользования или на этапе разработки, на мой взгляд, лучше сортировать свойства и методы (конечноотдельно друг от друга) по их функциональности, и каждую область озаглавливать общим комментарием. А в конце, иметь утилитку типа ASDoc, которая бы отформатировала код и расставила свойства и методы в алфавитном порядке.

На основании этой статьи уже можно создавать шаблон класса для FlashDevelop, но лучше - после следующей главы "Форматирование": Formatting.


пятница, мая 23, 2008

Хороший стиль Flex-программирования. Использование языка программирования

Продолжаем обозревать статью Flex SDK coding conventions and best practices.

Следующий подраздел: Language Usage.

Использование языка программирования

Здесь будут рассмотрены вопросы использования языковых конструкций ActionScript 3. Особое внимание мы уделим ситуацям, когда для выражения одной идеи существует несколько способов.

Параметры компиляции

Компилируйте проекты с параметрами -strict и -show-actionscript-warnings (они заданы по умолчанию в файле flex-config.xml).

API, базирующиеся на свойствах

Старайтесь применять API, которые базируются на свойствах а не на методах. Такой способ наиболее подходит для декларативного стиля программирования MXML.

Объявление типа

Указывайте типы для каждой константы, каждой переменной, каждого аргумента функции и ее результата. Даже если они не имеют типа, указывайте ":*":

Например:
можно: var value:*;
нельзя: var value;

Используйте наиболее подходящий для конкретной ситуации тип. Например, переменную цикла "for" лучше объявлять типом int а не Number, и, конечно, не Object или *. Другой пример: в mouseDownHandler необходимо объявить аргумент в виде event:MouseEvent, но не event:Event.

Используйте тип int для работы с целыми числами, даже если предполагается, что они будут только положительными. Тип uint используйте только для значений цветов RGB, битовых масок и в других значений, не предназначенных для вычислений.

Используйте тип * только в случае, если значение переменной может быть undefined. Но лучше всегда использовать вместо * тип Object, значение которого равно null, в случае, если объект не существует.

Если вы объявляете переменную типа Array, добавляйте комментарий /* of Тип */ непосредственно после слова Array, указывая тип элементов массива. Это важно, так как в будущих версиях ActionScript появятся типизированные массивы. (Интересно, такой синтаксис будет учитываться непосредственно компилятором, или это совет с расчетом на последующий рефакторинг кода?)

Например:
можно: var a:Array /* of String */ = [];
нельзя: var a:Array = [];
можно: function f(a:Array /* of Number */):Array /* of Object */ {...}
нельзя: function f(a:Array):Array


Литералы

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

int и uint
Никогда не используйте точку дроби в целочисленных значениях:
можно: 2
нельзя: 2.

В шестнадцатиричных числах всегда используйте "x" в нижнем регистре:
можно: 0xFEDCBA
нельзя: 0XFEDCBA

Всегда указывайте RGB-цвета в виде шестизначного шестнадцатиричного числа:
можно: private const BLACK:uint = 0x000000;
нельзя: private const BLACK:uint = 0;

При работе с индексами (например указатель на элемент в массиве), всегда используйте "-1" для обозначения отсутствия индекса.


Number
Если предполагается, что значение переменной будет дробным (обычный случай), инициировать его нужно с использованием точки дроби, после которой ставится дробная часть, либо, при ее отсутствии, нуль:
можно: alphaFrom = 0.0; alphaTo = 1.0;
нельзя: alphaFrom = 0; alphaTo = 1;

Но исключение для этого правила составляют пиксельные координаты, которые условно целые, хотя, в принципе, могут быть и дробными:
можно: var xOffset:Number = 3;
нельзя: var xOffset:Number = 3.0;

При использовании знака экспоненты, применяйте "e" в нижнем регистре:
можно: 1.0e12
нельзя: 1.0E12

Для Number используйте значение по умолчанию NaN - "не установлено".


String
Для обозначения строк всегда используйте двойные кавычки, даже если внутри строки присутствует символ кавычки:
можно: "What's up, \"Big Boy\"?"
нельзя: 'What\'s up, "Big Boy"?'

При использовании escape-последовательностей, спецсимвол "\u" указывайте в нижнем регистре:
можно: \u
нельзя: \U


Array
Используйте вместо new Array() литералы массива:
можно: [], [ 1, 2, 3 ]
нельзя: new Array(), new Array(1, 2, 3)

Используйте конструктор массива Array() только для определения массива заданного размера. Это важно, т.к. new Array(3) создает не [ 3 ], а [ undefined, undefined, undefined ].


Object
Используйте вместо new Object() литералы объекта:
можно: {}
нельзя: new Object(),

можно: {}, o = { a: 1, b: 2, c: 3 };
нельзя:
o = new Object();
o.a = 1;
o.b = 2;
o.c = 3;
или
o = {};
o.a = 1;
o.b = 2;
o.c = 3;



Function
Избегайте использования литералов функции для определения анонимных функций. Вместо этого, используйте методы класса или функции пакета.

При использовании литерала функции, обязательно указывайте возвращаемый тип, а последний оператор в теле функции заканчивайте символом точки с запятой ";":
можно: function(i:int):void { doIt(i - 1); doIt(i + 1); }
нельзя: function(i:int) { doIt(i - 1); doIt(i + 1) }


RegExp

Для определения регулярного выражения используйте представление в виде последовательности литералов, а не инстанцирование объекта RegExp с параметром String:
можно: var pattern:RegExp = /\d+/g;
нельзя: var pattern:RegExp = new RegExp("\\d+", "g");


XML и XMLList
Используйте представление в виде последовательности литералов, а не инстанцирование объекта XML с параметром String:
можно: var node:XML = <name first="Jane" last="Doe"/>;
нельзя: var node:XML = new XML("<name first=\"Jane\" last=\"Doe\"/>");

Используйте только двойные кавычки для определения значений аттрибутов тегов XML:
можно: var node:XML = <name first="Jane" last="Doe"/>;
нельзя: var node:XML = <name first='Jane' last='Doe'/>;


Class
Используйте полное имя класса (включающее имена пакетов) только в том случае, когда импортируется два класса с одним и тем же именем (но из разных пакетов), и необходимо разрешить конфликт имен:
можно:
import mx.controls.Button;
...
var b:Button = new Button();

нельзя:
import mx.controls.Button;
...
var b:Button = new mx.controls.Button();

Но в этом случае можно:
import mx.controls.Button;
import my.controls.Button;
...
var b:Button = new mx.controls.Button();



Выражения

Круглые скобки
При работе с операторами +, -, *, /, &&, , <, <=, >, >=, ==, и !=, не используйте круглые скобки там, где в этом нет необходимости:
можно: var e:Number = a * b / (c + d); var e:Boolean = a && b c == d;
нельзя: var e:Number = (a * b) / (c + d); var e:Boolean = ((a && b) (c == d));

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


Приведение типов
Не сравнивайте переменную типа Boolean с "true" или "false". Она уже является первым или вторым.
можно: if (flag)
нельзя: if (flag == true)
можно: var flag:Boolean = a && b;
нельзя: var flag:Boolean = (a && b) != false;

Явно приводите к типу Boolean переменные типа int, uint, Number или String:
можно: if (n != 0)
нельзя: if (n)
можно: if (s != null && s != "")
нельзя: if (s)

Переменные типа Object можно приводить к типу Boolean неявно:
можно: if (child)
нельзя: if (child != null)
можно: if (!child)
нельзя: if (child == null)

Лучше использовать приведение к типу (кастинг), чем оператор "as". Оператор "as" используйте только в том случае, если при ошибке приведения к типу, вы хотите получить в результате значение "null", а не генерацию исключения:
можно: IUIComponent(child).document
нельзя: (child as IUIComponent).document


Сравнение
Старайтесь расставлять сравниваемые значения в естественном для прочтения порядке (более удобном для прочтения порядке):
можно: if (n == 3) // "Если n равно 3"
нельзя: if (3 == n) // "Если 3 равно n"


Операторы ++ и --
Если в какой-либо ситуации префиксная и постфиксная формы (оператор ставится до или после переменной) логически равнозначны, используйте постфиксную форму. Используйте префиксную форму только в том случае, когда требуется получить значение переменной до ее изменения.
можно: for (var i:int = 0; i < n; i++)
нельзя: for (var i:int = 0; i < n; ++i)


Тернарный оператор

Ипользуйте вместо if/else тернарный оператор в случае простых операций проверки, особенно, для проверок значений на null:
можно: return item ? item.label : null;
нельзя:
if (!item) return null;
return item.label;

Однако, нельзя использовать вложенные тернарные операторы в сложных логических цепочках:
можно:

if (a < b)
return -1;
else
if (a > b)
return 1;
return 0;
нельзя:
return a < b ? -1 : (a > b ? 1 : 0);


Оператор new
Всегда используйте круглые скобки после имени класса, даже если конструктор не требует аргументов:
можно: var b:Button = new Button();
нельзя: var b:Button = new Button;

Операторы

Всегда ставьте после операторов точку с запятой ";". ActionScript 3 не считает за ошибку отсутствие точки с запятой в конце оператора, но лучше не пользоваться этой особенностью:
можно:
a = 1;
b = 2;
c = 3;
нельзя:
a = 1
b = 2
c = 3


Директива include
Используйте include вместо #include. В конце ставьте точку с запятой, как и для других операторов:
можно: include "../core/ComponentVersion.as";
нельзя: #include "../core/ComponentVersion.as"

Всегда используйте относительные пути вместо абсолютных.


Директива import
Указывайте только те классы, интерфейсы и пакетные функции, которые используйте. Не используйте спецсимвол "*":
можно:
import mx.controls.Button;
import flash.utils.getTimer;
нельзя: import mx.core.*;


Директива use namespace
Избегайте ее использования. Вместо этого, используйте синтаксис "::" для каждого определения вне основного пространства имен:
можно:
import mx.core.mx_internal;
// Позже, в каком-либо методе...
mx_internal::doSomething();
нельзя:
import mx.core.mx_internal;
use namespace mx_internal;
// Позже, в каком-либо методе...
doSomething();


Оператор if
Если ветви оператора if/else не содержат более одного оператора, не заключайте эти операторы в блок фигурными скобками.
можно: if (flag) doThing1();
нельзя: if (flag) { doThing1(); }
можно:

if (flag)
doThing1();
else
doThing2();
нельзя:
if (flag) {
doThing1();
}
else {
doThing2();
}

Однако, если одна из ветвей содержит более одного оператора, заключайте в блоки все ветви:
можно:

if (flag) {
doThing1();
}
else {
doThing2();
doThing3();
}
нельзя:
if (flag)
doThing1();
else {
doThing2();
doThing3();
}

Если требуется проверка большого количества ошибок, используйте последовательность операторов if, которые осуществляют проверку и при ошибке, сразу возвращают результат и выходят из метода. При этом, поток выполнения проверки движется по странице вниз. В конце метода ставится возврат результата успешного прохождения проверки.
Не используйте вложенные тесты, при которых поток выполнения смещается поперек страницы:
можно:

if (!condition1)
return false;
...
if (!condition2)
return false;
...
if (!condition2)
return false;
...
return true;
нельзя:
if (condition1) {
...
if (condition2) {
...
if (condition3) {
...
return true;
}
}
}
return false;


Оператор for
Всегда заключайте тело цикла в болк фигурными скобками, даже если оно состоит только из одного оператора.
можно:

for (var i:int = 0; i < 3; i++) {
doSomething(i);
}
нельзя:
for (var i:int = 0; i < 3; i++)
doSomething(i);

Используйте для хранения верхнего предела цикла локальную переменную. Это очень важно, поскольку верхний предел пересчитывается на каждой итерации цикла. Конечно, это не распространяется на те случаи, когда пересчет предела цикла необходим:
можно:

var n:int = a.length;
for (var i:int = 0; i < n; i++) {
...
}
нельзя:
for (var i:int = 0; i < a.length; i++) {
...
}

Определяйте переменную цикла внутри круглых скобок оператора цикла, если она не определяется где-либо повторно:
можно: for (var i:int = 0; i < 3; i++)
нельзя:

var i:int;
for (i = 0; i < 3; i++) {
...
}


Оператор while

Всегда заключайте тело цикла в болк фигурными скобками, даже если оно состоит только из одного оператора:
можно:

while (i < n) {
doSomething(i);
}
нельзя:
while (i < n)
doSomething(i);


Оператор do
Всегда заключайте тело цикла в болк фигурными скобками, даже если оно состоит только из одного оператора:
можно:

do {
doSomething(i);
} while (i < n);
нельзя:
do
doSomething(i);
while (i < n);


Оператор switch

Заключайте тело каждого выражения case и default в болк фигурными скобками. Операторы break или return ставьте внутрь блока, а не после него. Если вы используете в блоке return, не ставьте после него break. Вариант default обрабатывайте так же как и case, вызов break из него так же обязателен:
можно:

switch (n) {
case 0: {
foo();
break;
}
case 1: {
bar();
return;
}
case 2: {
baz();
return;
}
default: {
blech();
break;
}
}
нельзя:
switch (n) {
case 0:
foo();
break;
case 1: {
bar();
}
break;
case 2:
baz();
return;
break;
default:
blech();
}


Оператор return

Не заключайте возвращаемое значение в круглые скобки:
можно: return n + 1;
нельзя: return (n + 1);

Вызов оператора return разрешается из любого места тела метода.

Объявления

Никогда не объединяйте несколько констант/переменных в одно объявление:
можно: var a:int = 1; var b:int = 2;
нельзя: var a:int = 1, b:int = 2;


Ключевое слово override
Там, где override необходимо, указывайте его до объявления спецификатора доступа:
можно: override protected method measure():void
нельзя: protected override method measure():void


Спецификаторы доступа

Всегда указывайте спецификаторы доступа везде, где это можно сделать. Никогда не используйте то, что по умолчанию, спецификатором доступа является internal.

Перед тем, как объявить какой-либо API как public или protected, как следует подумайте, действительно ли это нужно. Public и protected API нужно документировать в обязательном порядке. Кроме того, они должны поддерживаться в нескольких последующих релизах, прежде чем станут формально устаревшими.


Ключевое слово static
Там, где static необходимо, указывайте его после объявления спецификатора доступа:
можно: public static const MOVE:String = "move";
нельзя: static public const MOVE:String = "move";


Ключевое слово final

Там, где final необходимо, указывайте его после объявления спецификатора доступа:
можно: public final class BoxDirection
нельзя: final public class BoxDirection

Объявляйте все классы-каталоги ("enum classes") как final.
Также, объявляйте "базовые" свойства и методы (те, что начинаются с $) как final.


Константы

Все константы должны объявляться как static. Нет необходимости объявлять в классе динамические константы, поскольку всё равно все объекты этого класса будут хранить одни и те же значения:
можно: public static const ALL:String = "all";
нельзя: public const ALL:String = "all";


Переменные

Если переменную необходимо инициализировать каким-либо значением, делайте это сразу при объявлении переменной, а не в конструкторе:
можно: private var counter:int = 1;
нельзя:

private var counter:int;
...
public function MyClass() {
super();
...
counter = 1;
}


Локальные переменные

Объявляйте переменны непосредственно при их применении, или перед их первым использованием. Не объявляйте все переменные в начале функции:
можно:

private function f(i:int, j:int):int {
var a:int = g(i - 1) + g(i + 1);
var b:int = g(a - 1) + g(a + 1);
var c:int = g(b - 1) + g(b + 1);
return (a * b * c) / (a + b + c);
}
нельзя:
private function f(i:int, j:int):int {
var a:int;
var b:int;
var c:int;
a = g(i - 1) + g(i + 1);
b = g(a - 1) + g(a + 1);
c = g(b - 1) + g(b + 1);
return (a * b * c) / (a + b + c);
}

Объявляйте локальные переменные в функции только один раз. ActionScript 3 не поддерживает объявление локальных переменных с областью видимости в одном блоке:
можно:

var a:int;
if (flag) {
a = 1;
...
}
else {
a = 2;
...
}
нельзя:
if (flag) {
var a:int = 1;
...
}
else {
var a:int = 2;
...
}

можно:
var i:int;
for (i = 0; i < n; i++) {
...
}
for (i = 0; i < n; i++) {
...
}
нельзя:
for (var i:int = 0; i < n; i++) {
...
}
for (var i:int = 0; i < n; i++) {
...
}


Классы
Если класс наследуется от Object, не нужно указывать extends Object.

The only “bare statements” in a class should be calls to static class initialization methods, such as loadResources(). (Совсем ничего не понял в этой фразе).


Конструкторы
Если класс имеет какие-либо свойства или методы, необходимо написать конструктор. Обязательно вызывайте super(), даже если кроме него больше ничего нет.

Если в конструктор передаются аргументы, давайте им имена переменных, которым они передаются.
можно:

public function MyClass(foo:int, bar:int) {
this.foo = foo;
this.bar = bar;
}
нельзя:
public function MyClass(fooVal:int, barVal:int) {
foo = fooVal;
bar = barVal;
}

Не инициализируйте переменные класса в конструкторе. Делайте это при объявлении переменных. Это разрешается только в том случае, когда в наследуемых классах требуется переустановить значения переменных.

Послесловие

Далее перечислены темы, которые еще не в разработке:

  • Interfaces
  • Namespaces
  • Implementing properties
  • Metadata
  • Packages
  • Helper classes
  • Bare statements

Будем иногда заглядывать СЮДА и следить за продолжением.

Правила, конечно, порой спорные.
Например, инициализация переменных при их объявлении допустима только при работе с простыми значениями. [Например, инициализировав какую-либо переменную объектом {prop:1}, мы получим во всех объектах этого класса ссылку на один и тот же объект, но не клоны отого объекта.]

Еще пример - избавляться от лишних круглых скобок в вычислениях и логических выражениях. Не сильно я согласен с таким заявлением. Вообще, код лучше читается, когда он поделен на блоки. При многочисленных делениях и умножениях трудно будет потом разобраться что на что делется и множится... То же самое в логических выражениях.

Остальное, в принципе, вполне законно и приемлемо.
В следующий раз поговорим об организации файлов: File Organization.

среда, мая 21, 2008

Хороший стиль Flex-программирования. Именование

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

Adobe любит нас, и создал для нас небольшой свод правил, который поможет не только лучше понимать Flex SDK, но и нам самим сделать свой код лучше:
Flex SDK coding conventions and best practices

Итак, сегодня мы поговорим об именовании (Naming).

Именование

Наши стандарты именования соответствуют стандартам ECMAScript и Flash Player 9.


Использование сокращений

Вообще, лучше их избегать. Например:
можно: calculateOptimalValue(), нельзя: calcOptVal().

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

Однако, есть общепринятые сокращения:
acc = accessibility (ButtonAccImpl)
auto = automatic (autoLayout)
eval = evaluate (EvalBindingResponder)
impl = implementation (ButtonAccImpl)
info = information (GridRowInfo)
num = number (numChildren)
min = minimum (minWidth)
max = maximum (maxHeight)
nav = navigation (NavBar)
regexp = regular expression (RegExpValidator)
util = utility (StringUtil)

Существуют и другие сокращения. Если мы не догадаемся об их смысле, придется поискать их применение в исходном коде. Или подумать еще разок.

Иногда можно встретить отсутствие логики в применении сокращений. Например, horizontalScrollPolicy и verticalScrollPolicy, но HBox и VBox.


Использование аббревиатур

Аббревиатуры довольно часто используются во Flex: AIR, CSS, HLOC, IME, MX, MXML, RPC, RSL, SWF, UI, UID, URL, WSDL, XML.

Аббревиатуры всегда пишутся либо заглавными, либо строчными буквами:
можно: SWF, swf, нельзя: Swf

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

Например:
можно: CSSStyleDeclaration, IUID, uid, IIME, imeMode.


Разделение слов

Когда идентификатор состоит из двух или более слов, используется два метода разделения слов:
- Регистром - каждое отделяемое слово пишется с большой буквы
- Подчеркиванием - слова разделяются символом подчеркивания

В некоторых местах может встретиться нарушение этого правила: комбинация слов становится целым словом: dropdown, popUp, pulldown.


Имена, содержащие тип

Если в имени нужно указать тип, поместите его, не сокращая, в конец имени. Откажитесь от использования суффиксов типа "_mc" по старой традиции ActionScript 1.

Например:
можно: border, borderSkin, or borderShape, нельзя: border_mc

Часто лучшим именем для объекта является имя его типа в отличающемся регистре (не соглашусь, т.к. смысловой нагрузки никакой - годится только для тестов и примеров):
var button:Button = new Button();


Имена пакетов

Начинаются со строчной буквы и для разделения слов используется регистр: controls, listClasses.

Имена пакетов должны быть всегда существительными или отглагольными -ing формами (герундий), но не глаголами, прилагательными или наречиями.

Пакет, включающий множество схожих элементов должен именоваться общим названием этих элементов во множественной форме: charts, collections, containers, controls, effects, events ...

Обычно, -ing формами именуются пакеты, реализующие концепции (я бы сказал процессы): binding, logging, messaging, printing ...
С другой стороны, это могут быть существительные, выражающие концепцию: accessibility, core, graphics, rpc ...

Пакет, содержащий классы, которые обеспечивают работу компонента FooBar, должен называться fooBarClasses.


Имена файлов

Имена файлов импортируемых API должны соответствовать определениям public API. Но для include-файлов (файлов фрагментов кода) это правило не применяется.

Имя include-файла начинается с заглавной буквы и разделение слов в имени осуществляется регистром: BorderStyles.as, ModalTransparencyStyles.as

Имена файлов ресурсов пишутся строчными буквами, а слова разделяются символом подчеркивания: icon_align_left.png


Имена пространств имен

Именуются строчными буквами с разделением слов символом подчеркивания: mx_internal, object_proxy.


Имена интерфейсов

Начинаются с заглавной "I", разделение слов в имени осуществляется регистром: IList, IFocusManager, IUID.


Имена классов

Начинаются с заглавной буквы, разделение слов в имени осуществляется регистром: Button, FocusManager, UIComponent.

Подклассы Event именуются FooBarEvent.
Подклассы Error именуются FooBarError.
Подкласс EffectInstance, ассоциированный с эффектом компонента FooBar именуется FooBarInstance.
Подклассы Formatter именуются FooBarFormatter.
Подклассы Validator именуются FooBarValidator.
Классы скинирования компонентов именуются FooBarBackground, FooBarBorder, FooBarSkin, FooBarIcon, FooBarIndicator, FooBarSeparator, FooBarCursor, и т.д.
Классы утилит именуются FooBarUtil (не FooBarUtils - пакет может именоваться во множественном числе, но класс - только в единственном).
Общепринято базовый класс именовать FooBarBase: ComboBase, DateBase, DataGridBase, ListBase.


Имена событий

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: move, creationComplete.


Имена стилей

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: color, fontSize.


Значения строковых свойств

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: "auto", "filesOnly".


Имена констант

Именуются полностью заглавными буквами с разделением символом подчеркивания: OFF, DEFAULT_WIDTH.

Если константа строковая, слова в имени константы должны соответствовать словам в строке ее значения:
public static const FOO_BAR:String = "fooBar";


Имена свойств (переменные и установщики)

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: i, width, numChildren.

Используйте "i" для имени переменной цикла "for", и "n" для имени верхнего предела цикла.
Используйте "j" для имени переменной вложенного цикла "for", и "m" для его имени верхнего предела цикла:
for (var i:int = 0; i < n; i++)
{
for (var j:int = 0; j < m; j++)
{
...
}
}

Используйте "p" для имени переменной цикла "for..in":
for (var p:String in o)
{
...
}

Бывают ситуации, когда в классе необходимо переопределить установщик, но предполагается, что базовый установщик будет продолжать использования. Для сохранения базового установщика, необходимо создать новый установщик, имя которого должно формироваться путем добавления к имени базового установщика символа "$". Полученный установщик нужно определить как "final". Он не должен ничего делать, кроме вызова базового установщика. Напимер, нам нужно перекрыть установщик numChildren, но при этом сохранить возможность вызывать базовый super.numChildren - для последнего мы создаем следующее:
mx_internal final function get $numChildren():int {
return super.numChildren;
}


Переменные для хранения данных установщиков

К имени установщика добавляется символ подчеркивания "_":
для foo имя переменной _foo.


Имена методов

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: measure(), updateDisplayList().

Имена методов должны быть всегда глаголами.

Лучше не использовать методы без параметров подобно getFooBar() или setFooBar(). Вместо них используйте установщики. Однако, если getFooBar() - медленный метод, требующий больших вычислений, лучше его назвать findFooBar(), calculateFooBar(), determineFooBar(), и т.д., выражая его суть, а не то, что он способен возвращать что-либо.

Аналогично установщикам, если базовый метод перекрывается, но требуется сохраненить доступ к нему, создается метод с именем базового метода, перед которым добавляется символ "$":
mx_internal final function $addChild(child:DisplayObject):DisplayObject
{
return super.addChild(child);
}


Обработчики событий

Имя обработчика события формируется путем добавления к имени типа события слова "Handler": mouseDownHandler().

Если обработчик предназначен для событий, отправленных субкомпонентами (т.е. не this), перед именем обработчика, сформированного по вышеописанному правилу, добавляется имя субкомпонента, отделенное символом подчеркивания "_": textInput_focusInHandler().


Имена аргументов

Всегда используйте для установщиков имя аргумента "value":
можно - public function set label(value:String):void
нельзя - public function set label(lab:String):void
нельзя - public function set label(labelValue:String):void
нельзя - public function set label(val:String):void

Всегда используйте для обработчиков событий имя аргумента "event":
можно - protected function mouseDownHandler(event:Event):void
нельзя - protected function mouseDownHandler(evt:Event):void


Имена пакетов ресурсов

Если пакет рессурсов содержит ресурсы для определенного пакета классов, имя пакета рессурсов должно быть таким же: controls, {formatters}}, validators.


Имена идентификаторов ресурсов

Начинаются со строчной буквы, разделение слов в имени осуществляется регистром: pm, dayNamesShort.


Прочая терминология

Избегайте использование слова "object", т.к. оно вносит неопределенность.

Слово "item" - элемент данных и никогда DisplayObject.

Слово "renderer" - это DisplayObject, который отображает элемент данных.

Слово "type" означает тип AS3, используйте вместо него слово "kind".

С именованием разобрались. Теперь попытаемся придерживатся этих правил на практике. У меня есть много своих правил именования, и скорее всего часть из них я оставлю (например именовать private-свойства с префиксом в два подчеркивания, а protected-в одно), но правила, принципиально идущие вразрез с вышеприведенными надо искоренять.

Следующий раздел "Language Usage" разберем в ближайшее время.

вторник, мая 20, 2008

Немногодетный Loader. AS3

Loader может хранить всего один визуальный объект. Попытка загрузки в один и тот же Loader более одного раза заканчивается генерацией исключения.
Кроме того, как сказано в хелпе, вызов методов: addChild(), addChildAt(), removeChild(), removeChildAt(), and setChildIndex(). также закончится неудачей.

Но Loader любит своего единственного малютку, и если мы захотим покуситься на него, нам придется убить самого Loaderа.

понедельник, мая 19, 2008

Куда переползли FlashVars. AS3

В ActionScript 2.0 Migration не указывается куда делись FlashVars в AS3.
Поэтому простым поиском в Help-е находим что:
Класс flash.display.LoaderInfo имеет свойство parameters:Object в которое складируются в виде ассоциативного массива параметры URL-строки SWF-файла и параметры строки FlashVars, которые действительны только для главного SWF.
Добраться до него легко, используя свойство основного flash-клипа loaderInfo:
for (var name:String in this.loaderInfo.parameters) {
trace(this.loaderInfo.parameters[name]);
}

пятница, мая 16, 2008

Из Flex Builder во FlashDevelop

Судьба распорядилась так, что временно приходится перебросить разработку Flex-проекта с Flex Builder на FlashDevelop. Заодно проверить, как последний с этим справится.

Установил последнюю версию FlashDevelop 3.0.0 Beta7. Теперь в пустом окне "Project" есть очень заманчивая кнопка "Import a Flex project", которой я немедленно и воспользовался. FD быстренько подхватил папку Flex-проекта и поместил в нее свой файл *.as3proj. Теперь можно спокойно работать как с обычным FD-проектом.

Первая нехорошая особенность - кодировка файлов, созданных FB распознается не правильно, и приходится постоянно корректировать кодировку файлов.

При компиляции проекта, получаем ексцепшн: "Error: null java.lang.NullPointerException...
Build halted with errors (mxmlc)"
. Хорошенькое дело. Ищем причину. Аналогичная ошибка имеет место не только у меня одного. Причина кроется в какой-то ошибке при внедрении шрифта. Как только я убрал

@font-face {
font-family: localArial;
font-weight: normal;
src: local("Arial");
...
}

Ошибка пропала, но такой вариант совсем негодится. Жаль, но на этом прийдется остановиться, пока не узнаю, как побороть этот недостаток...

четверг, мая 15, 2008

Откуда начинается XML. AS3

Всё время возникает путаница.
Есть XML:
<?xml version="1.0" encoding="utf-8" ?>
<data>
<item>Раз</item>
<item>Два</item>
</data>

После его загрузки, он отправляется в переменную:
private var __xml:XML;

. . .

private function onComplete(event:Event):void {
this.__xml=new XML(event.target.data).normalize();
}


Далее, мы хотим получить первый элемент списка и по логике (старой доброй логике AS2) пишем:
trace(this.__xml.data.item[0]);
Но получаем эксцепшном по лбу: "Error #1010: A term is undefined and has no properties.".
Потому что надо так:
this.__xml.item[0]
Контейнерный тег data (вместо data может быть любое другое слово) и будет являться нашим this.__xml.

Делаем прелоадер для Flex-приложения. Продолжение. AS3

Поиск привел к статейке: Making a Cooler Preloader in Flex: Part 1 of 3.

Доступно, с примерами раскрывается процесс создания собственного прелоадера для Flex-приложения. Пожалуй, выделю основные положения, опустив приступы остроумия автора :).

Введение.

Для создания собственного прелоадера для Flex, необходимо всего два шага:

  1. Расширить класс DownloadProgressBar.
  2. Указать Application, в свойстве preloader, этот новый класс.

Или подробнее:

  1. Создать MovieClip, содержащий 100 фреймов.
  2. Указать ему Linkage ID без имени класса.
  3. Скомпилиоровать SWF.
  4. Написать собственный прелоадер, использующий созданный Flash MovieClip.
  5. Указать в mxml-коде, в теге mx:Appliction свойство preloader с именем созданного класса.

Создание Flash клипа

Автор предлагает создать 100-фреймовый клип с анимацией отображения прогресса загрузки, и добавляет в него dynamic TextField. Полученный клип он убирает в другой клип-контейнер, содержащий таймлайн с плавной анимацией появления и скрытия прелоадера. При этом необходимо дать имена всем клипам, участвующим в доступе к 100 фреймам и текстовому полю, для того, чтобы затем обратиться к ним по принципу “dot dot down” (это оказывается у нашего брата флэшера существует такой сленг, означающий "спуск" по дереву клипов к объекту, с которым нужно взаимодействовать).

Важно: Никаких скриптов в таймлане не пишем.

Затем - что еще любопытнее - автор экспортирует всё это хозяйство во Flash 8, AS2 или AS1. Как он это объясняет, если делать прелоадер под AS3, то потребуется писать класс для прелоадера, а это повлечет за собой массу работы и дополнительного объема к файлу. Наш прелоадер должен быть простым и максимально легким.

Итак, экспортируем в Flash 8, а в Linkage указываем идентификатор и ставим 1-ю и 3-ю галки. Flex должен увидеть наш Linkage ID, когда мы внедрим наш SWF.

Класс прелоадера

Создаем класс, экстендим его от mx.preloaders.DownloadProgressBar. Внедряем в него Flash контент мета-тегом [Embed(source="... /preloader.swf", symbol="Preloader")]. В конструкторе создаем и добавляем в дисплей-лист объект прелоадера. Затем, перекрывая свойство-установщик preloader, назначаем обработчики событий загрузки.

Важный момент: для того, чтобы организовать плавное скрытие прелоадера, нобходимо прибегнуть к следующему трюку. Мы предусмотрели в клипе-контейнере анимацию скрытия прелоадера (которая заканчивается, к примеру, на 20-м фрейме, а фрейм 21 пуст) . По событию onFlexInitComplete, мы добавляем скрипт в фрейм 21: clip.addFrameScript(21, onDoneAnimating);. Наш скрипт останавливает анимацию прелоадера и генерирует событие Event.COMPLETE.

Важное добавление в комментариях: В коде обработчика onDoneAnimating необходимо отписаться от всех событий, на которые подписался класс прелоадера.

Пример и исходники прилагаются: Example Source ZIP.

Попробуем, как это работает на практике.

* * *

Попробовал. Работает. Но пришлось убить часа два на следующую проблему: В примере в главном клипе скрипт устанавливается во фрейм 21. Я создал клип с таймлайном в 21 фрейм. Не заработало. Скачал пример: Download Preloader FLA. Заработало. Подменил своим - не заработало (клип крутится по кругу, но не стартует скрипт).

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

* * *

Выяснилось, что не обязательно использовать версию Flash8 AS2. Можно указать и Flash 9 с AS3. Однако как ни крути, скрипты из тайм-лайна вызываться не будут. В целях снижения объема SWF-файла лучше всеже использовать более старые версии - лучший результат показал Flash 6/7 AS1/AS2, но не намного.

* * *

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

  1. Добавить в пункте "Additional compiler arguments:" строку:
    -default-background-color #336699
  2. Указать цвет фона в параметрах тегов Object и Embed при внедрении флэш-приложения в HTML-страницу:

понедельник, мая 12, 2008

Баг при выходе пользователя из комнаты. AS3. SmartFoxServer

Генерируется исключение (TypeError: Error #1009: Cannot access a property or method of a null object reference.) в модуле it.gotoandplay.smartfoxserver.handlers.SysHandler, версия модуля 1.2.0, в строке 348:
var uName:String = theRoom.getUser(userId).getName()

Генерируется клиентом при выходе из комнаты какого-либо другого пользователя, при условии, что до этого был вызван метод this.__sfs.getRoomList(); и обработано событие onRoomListUpdate.
Коррекция ошибки заключается в проверке на null метода theRoom.getUser(...):
var uName:String = "";
if (theRoom.getUser(userId)!=null)
uName = theRoom.getUser(userId).getName()

Ненавижу корректировать чужой код, но тут другого выхода не вижу.

среда, мая 07, 2008

Принцип перебора for .. in . AS3

Столкнулся с интересной проблемой.
Есть ассоциативный массив:
static private const distribution:Object = {item1:2,item2:2,item3:2};
Осуществляю перебор элементов:


. . .

this.__distribution=distribution;

. . .

for (var name:String in this.__distribution) {
count=int(this.__distribution[name]);

. . .

}

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

Ничего удивительного, в хелпе об этом так и сказано:
Iterates over the dynamic properties of an object or elements in an array and executes statement for each property or element. Object properties are not kept in any particular order, so properties may appear in a seemingly random order.

Именование безымянных клипов. AS3

Есть SWF с кучей клипов.
Он подгружается во Flex-приложение.
Flex-приложение перебирает содержимое SWF:
for (var i:int=0; i<this.__template_container.numChildren; i++) {

. . .

}

Клипам, которым небыли назначены имена, Flash присвоил имена по умолчанию типа instanceXXX. И что самое интересное, этот XXX не поддается никакому очевидному принципу. Либо на разных компьютерах, либо в разных версиях запуска приложения, одним и тем же клипам назначаются разные числа.

Поэтому, нельзя надеяться на имена "по умолчанию". Если раньше, в AS2 можно было быть уверенным, что где-то на сцене присутствует instance0, то теперь об этом лучше даже не думать. Конечно, потребность в таких именах невелика, но порой может сбить с толку, например при отладке.

четверг, мая 01, 2008

FLVPlayback и ошибка 1000. AS2

Столкнулся с тупейшей проблемой.
Есть FLVPlayback с именем video (со свойствами по умолчанию).
По клику на кнопку b1 указывается:
video.contentPath="URL существующего файла";
По клику на кнопку b2 указывается:
video.contentPath="URL несуществующего файла";
По клику на b1 видео воспроизводится. По клику на b2, видео, если оно воспроизводилось, останавливается, если нет - ничего не происходит. Теперь, при повторном нажатии на b1, мы ожидаем снова увидеть наше видео, но.... получаем ошибку:
1000: Unable to make connection to server or to find FLV on server
Что бы я не делал - вызывал разные методы типа stop/play, менял свойства компонента - всё безрезультатно.

После того, как state уходит в состояние CONNECTION_ERROR компонент работать отказывается.

Пока вижу одно решение - перед запуском видео, проверять наличие файла.