Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Первое обращение к статику (http://www.flasher.ru/forum/showthread.php?t=175728)

in4core 22.02.2012 23:29

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

Есть класс загрузки скинов , и класс в котором идет работа с элементами скина.
Рассмоьтрим второй класс

Код AS3:

class ManagerSkin {
 
private static var element:MovieClip = Skins.getElement();
 
}

Так вот, теперь рассмотрим ситуацию, что инстанс ManagerSkin еще не готов , а так же Skins не прошел инициализацию, напишем :
ManagerSkin.setVar(0) // некий метод не имеющий отношение к Skins

В итоге после этого, как только инстанс будет создан и будет обращение к element мы получим ошибку. (1009)

Тоесть вывод : как только мы первый раз обращаемся к классу со статическими переменными - ВСЯ его статика сразу же инициализируется.

Честно говоря, я думал, что инициализация статики происходит ТОЛЬКО после обращения к ней напрямую, и не зависит от того, что ты стучишься к другим переменным.

expl 22.02.2012 23:44

Инициализация статик классов непредсказуема.
Но можно гарантировать выполнение кода перед обращением ленивой инициализацией:
Код AS3:

public static getElement():MovieClip
{
    if (!_inited)
    {
        init();
    }
    ...
    return _element;
}

Соответсвенно все присваивания статичным полям поместить в этот init().
Однако, если у тебя есть несколько статических классов, ссылающихся при инициализации друг на друга - разработка обещает быть весёлой :)

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

Ещё можно у каждого статик-класса создать метод init(). И вызвать при старте приложения все init() в нужном порядке - это сделает код гораздо прозрачнее.
Но все присваивания полям должны быть либо линивыми либо в коде init()!

in4core 22.02.2012 23:58

На самом деле случайно нарвался на этот момент. У меня суть в том, что часть классов ( типа синглтон ) имеют только 1 инстанс, соотв в таких случаях я по обычке ВСЕ переменные такого класса задаю как статик или статик конст ( ну ежели и переменная не будет меняться ) при этом класс не статичный , это касается тока переменных.
А тут случайно вызвал утилитный метод отдельно и попал в просак) искал ошибку часа 1.5 ))

expl 23.02.2012 00:04

Цитата:

У меня суть в том, что часть классов ( типа синглтон ) имеют только 1 инстанс, соотв в таких случаях я по обычке ВСЕ переменные такого класса задаю как статик или статик конст ( ну ежели и переменная не будет меняться ) при этом класс не статичный , это касается тока переменных.
Если класс синглтон, зачем все его поля делать статичными? Они же все равно 2 раза _не_ проинициализируются. А если они будут инициализироваться в конструкторе синглтона или как присвоения обычным полям - то есть полная гарантия, что при обращении к синглтону через getInstance все они будут проинициализированы. Со статикой такой гарантии нет.

А вот если проблемы возникают с внешней либой построенной на статичных классах - опиши по-подробнее - тут придется выкручиваться по ситуации.

in4core 23.02.2012 00:11

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

Aquahawk 23.02.2012 00:21

Цитата:

как только мы первый раз обращаемся к классу со статическими переменными - ВСЯ его статика сразу же инициализируется.
Да истинно так. Советую прочитать avm2 overview многие подобные вопросы отпадут. В частности то что вызывается при первой инициализации называется cinit и туда свалится весь код инициализации, кроме константных значений некоторых типов, они в структуре класса будут представлены в виде значений по умолчанию.
Причём cinit это обычный метод, туда можно код понаписать:
Код AS3:

class ManagerSkin {
 
private static var element:MovieClip = Skins.getElement();
trace("hello from cinit");
 
}

Чтобы это лучше понять можно взять что-нибудь из хороших тулзов для реверсинга и декомпильнуть свой проект. Например rabcdasm.

Добавлено через 36 минут
Цитата:

Инициализация статик классов непредсказуема.
Неправда. Очень даже предсказуемо. Инициализация произойдёт в момент первого обращения к типу, т.е. создания переменной, при получении getDefenitionByName и т.п.
Если мы создадим два класса сто статическими полями и кросс ссылками друг на друга то это упадёт в рантайме т.к. во втором сините мы попробуем получить другой тип который ещё не проинитился и вместо него получим null

expl 23.02.2012 15:50

Т.е. что, получается если нет кросс-ссылок, а мы содим вот такую весчь:
Код AS3:

public class A
{
    public static var a:int = B.b;
}
public classB
{
    public static var b:int = 10;
}

То а гарантированно получит значение 10?
Вообще да, проверил работает, действительно предсказуемо.

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

Поэтому думал что он вообще как повезёт их инициализирует.
Вобщем, дров наломать можно.

С внутренними классами вообще всё безобразно:
Код AS3:

package {
        import flash.display.Sprite;
        public class Example extends Sprite {
                // Падает со словами "Inner не является конструктором."
                public static var INNER:Inner = new Inner();
                public function Example() {
                        trace(INNER);
                }
        }
}
class Inner {}

А так не падает:
Код AS3:

package {
        import flash.display.Sprite;
        public class Example extends Sprite {
                private static var _INNER:Inner;
                public static function get INNER():Inner {
                        if (_INNER == null) {
                                _INNER = new Inner();
                        }
                        return _INNER;
                }
                public function Example() {
                        trace(INNER);//[object Inner]
                }
        }
}
class Inner {}



Часовой пояс GMT +4, время: 23:20.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.