Присвоение существующего CGColor свойству CGColor работает в iOS Simulator, а не на устройстве iOS.Зачем? - PullRequest
8 голосов
/ 10 февраля 2012

Я знаю, как решить проблему, которую я собираюсь обрисовать, однако я немного озадачен тем, почему сценарий кода работает в симуляторе iOS, а не на моем iPad.

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

//This will be the CALayer BGColor...
CGColor c = UIColor.blueColor.CGColor; //Blue is the default
switch (myState)
{
    case state_one:
        c = UIColor.greenColor.CGColor;
        //... more code ...
        break;
    case state_two:
        c = UIColor.redColor.CGColor;
        //... more code ...
        break;
    case state_three: //multiple cases are like the state_three case.
        //Other code, but I don't need to assign the color.  Blue works...
}

myCALayer.backgroundColor = c; //Oh-noes!!! Here we get the dreaded EXC_BAD_ACCESS on iPad
//...more code dealing with the layer.

Код выше работает без проблем в симуляторе.Однако, когда я запускаю приложение на своем iPad, оно падает при назначении backgroundColor.

Я могу исправить это, избавившись от переменной CGColor и назначив цвет фона непосредственно из моего оператора switch / case, и это то, что я планирую сделать.

Однако мне любопытно.Почему это работает в одной среде, а не в другой?

ОБНОВЛЕНИЕ

Пара вещей.Во-первых, стоит упомянуть, что это проект ARC, использующий Xcode 4.2 и предназначенный для устройств iOS 5.Кроме того, мой код назначения цвета не совсем такой, как он выглядит, потому что у меня есть ряд определений, которые я использую для установки этих цветов, потому что на них ссылаются во всем приложении.

Это то, что некоторые из#define операторы выглядят так:

#define BLUE  [UIColor colorWithRed:8.0/255.0 green:80.0/255.0 blue:150.0/255.0 alpha:1.0].CGColor
#define GREEN (UIColor.blueColor.CGColor)
//...and there are about 6 other colors

Я попытался упростить свой код, потому что компилятор должен заменить ссылки на мои ссылки на мои определения.Тем не менее, стоит упомянуть на всякий случай.

Ответы [ 3 ]

8 голосов
/ 10 февраля 2012

Вот моя догадка: возможно, что UIColor, который его создал (и удерживал единственную ссылку), был уничтожен до того, как вы передадите CGColor.Поскольку подсчет ссылок CGColorRef не выполняется для вас в ARC, цвет будет зависать, если UIColor, удерживавший его, был уничтожен до того, как вы используете CGColor.

ARC имеетоптимизация, при которой объекты с «автоматическим выпуском» никогда не могут быть добавлены в пулы с автоматическим выпуском, и вместо этого released после объекта objc больше не упоминается.Это сочетание трех вещей:

  1. Версия компилятора и используемые вами опции.Неудивительно, что компилятор добавляет подсчет ссылок, и для этого есть разные варианты.
  2. The ObjC Runtime.Среда выполнения может использовать локальные данные потока.Естественно, это может включать ваш стек.Если вы прочитаете подробности о том, как объект может обойти пул авто-релиза, это должно быть понятнее.
  3. Библиотеки, которые вы используете (включая системные библиотеки и фреймворки).По мере обновления компилятора и среды выполнения библиотеки могут использовать ARC или другие вызовы среды выполнения для выполнения программы.

Зная, что эта программа исправит проблему:

UIColor * c = UIColor.blueColor; //Blue is the default
switch (myState) {
    case state_one:
        c = UIColor.greenColor;
        //... more code ...
        break;
    case state_two:
        c = UIColor.redColor;
        //... more code ...
        break;
    case state_three: //multiple cases are like the state_three case.
        //Other code, but I don't need to assign the color.  Blue works...
}

myCGLayer.backgroundColor = c.CGColor;
//...more code dealing with the layer.

Более подробно, существует ряд способов, которыми компилятор и среда выполнения objc могут интерпретировать и выполнить вашу программу.Это означает, что эта проблема может затронуть вас при изменении версий компилятора или при обновлении среды выполнения (ОС).Это также может произойти, когда используемые вами библиотеки обновляются или создаются с различными версиями или настройками компилятора.Например: если по пути библиотека переключается на ARC, она может использовать другие вызовы времени выполнения или вызовы могут использовать локальные данные потока по-разному, если обновляются вызовы, введенные компилятором.

Подробности о спецификации ARC приведены ниже.это относится к среде выполнения можно найти здесь: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime


Аналогичная проблема была замечена здесь:

EXC_BAD_ACCES рисование тени

6 голосов
/ 01 декабря 2012

Из-за ARC цвет высвобождается слишком рано в конце метода.

я использую: CGColorRetain

CGColorRef whiteColor = CGColorRetain([UIColor colorWithRed:1.0 green:1.0
                                         blue:1.0 alpha:1.0].CGColor);
0 голосов
/ 10 февраля 2012

Вы не говорите, что ваш экземпляр myCGLayer нами получен, но я сделаю снимок и скажу, что он не получен из CGLayer, потому что CGLayer не имеет свойства backgroundColor.Таким образом, я предполагаю (снова), передаваемый параметр должен иметь тип UIColor, а не CGColor.CGColor является производным от класса CFType.UIColor является производным от NSObject.Они не должны быть взаимозаменяемыми.Если мои догадки верны, я удивляюсь, что это работает в симуляторе.

Не бейте меня слишком сильно, если мои догадки неверны.

...