2016-04-14 4 views
3

У меня возникла проблема с освобождением экземпляров NSObject, когда я не ожидаю. У меня есть переменная формы типа NSNumber, в button1 я создаю экземпляр и устанавливаю значение, в button2 я читаю значение. Если я не назову удержание в кнопке 1, тогда переменная освобождается, и приложение зависает, когда я нажимаю кнопку2, добавление вызова для сохранения заставляет все работать.Delphi XE6 ARC для переменных OSX, освобождающих

Это на OSX, используя Delphi XE6 с firemonkey.

Вот код

Определение формы переменной типа NSNumber

Fv : NSNumber; 

Теперь добавьте пару кнопок

для Button1Click

begin 
    Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0)); 
    ShowMessage(IntToStr(Fv.retainCount)); // value is 1 
    Fv.retain; // comment out this to make it crash on button2 click 
    ShowMessage(IntToStr(Fv.retainCount)); // value is 2, or 1 without the retain 
end; 

для Button2click

Теперь, похоже, что это происходит в конце нажатия кнопки Button1, delphi освобождает Fv, уменьшая счетчик ссылок, то есть он действует как выход из области видимости. Поэтому, чтобы FV зависать, мне нужно добавить Fv.retain. Если я нажму кнопку2 без сохранения, то он сработает.

Должен ли я занять удержание - я не думал, что это необходимо, или я пропускаю что-то еще?

ТИА

+1

То же самое происходит при ориентации на iOS. Когда я обертываю объекты Objective-C, мне иногда приходится вызывать сохранение, а иногда и нет. Не понял, в чем разница, но легко обнаружить, когда требуется сохранение :-) – Hans

+0

Я не знал, что компилятор OS X XE 6 реализовал ARC. Я думал только о iOS и Android? –

+2

FWIW, 'numberWithFloat()' вероятно, генерирует переменную autorelease (большинство «конструкторов удобства»). Они действительно должны быть сохранены, чтобы держать их вокруг дольше, чем до следующего цикла авторекламы. –

ответ

2

Благодаря @RudyVelthius и @RemyLebeau за поставив меня на правильный путь.

Проблема не проблема Delphi, а объективная проблема C (по крайней мере, мое понимание цели C является проблемой).

TNSNumber.OCClass.numberWithFloat(4.0) 

является удобство конструктор - это означает, что его добавили в пул выпуска авто, и освобожденный в следующий раз основной цикл запуска выполняет.

Так что мой интерфейс delphi в порядке, но, к сожалению, он указывает на то, что уже не существует. Сохранять переменную autorelease вокруг вызова. Просто чтобы доказать, что проблема, вызывающая alloc/init, должна ее исправить. так

заменить

Fv := TNSNumber.Wrap(TNSNumber.OCClass.numberWithFloat(4.0)); 

с

Fv := TNSNumber.Wrap(TNSNumber.Alloc.initWithDouble(4.0)); 

и удалите сохранить и все это работает.

здесь https://stackoverflow.com/a/801000/416047 правило является

Если селектор возвращающий объект имеет слово «новый», «Alloc», «сохранить» или «копировать» в нем, то у вас есть возвращенный объект и являются , ответственными за освобождение, когда вы закончите.

В противном случае вы не являетесь владельцем и не должны его выпускать.Если вы хотите, чтобы сохранил ссылку на объект, не принадлежащий ему, вы должны позвонить - [NSObject сохранить] в этом экземпляре. Теперь вы «владеете» этим экземпляром и должны , поэтому вызов - [NSObject release] в экземпляре, когда вы закончите с . Таким образом, вы не являетесь владельцем экземпляра, возвращаемого - [NSNumber numberWithInt:] и не должны вызывать -release на нем, когда вы закончите. Если вы хотите сохранить возвращаемый экземпляр за пределами текущей области действия (действительно за пределами срока действия текущего экземпляра NSAutoreleasePool ), вы должны его получить.

Смежные вопросы