EXC_BAD_INSTRUCTION при синтезе @property (слабый) IBOutlet NSWindow * окно - PullRequest
5 голосов
/ 26 октября 2011

Я новичок в разработке ObjC / Cocoa и Mac в целом, и увлекаюсь основами.

Упрощенный шаблон по умолчанию для нового приложения Какао в Xcode 4.2 на Lion выглядит следующим образом:

// AppDelegate.h
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;

@end



// Appdelegate.m
#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}

@end

Я использовал это в качестве основы для различных экспериментов. Читая об Автоматическом подсчете ссылок (который проект будет использовать) - эта статья, например - я предположил, что можно, возможно, даже должен заменить assign квалификатор для NSWindow *window с weak, но, похоже, это не так.

Приложение работает нормально, но зависает при запуске, с Thread 1: Program received signal: "EXC_BAD_INSTRUCTION" в AppDelegate.m на строке с @synthesize window = _window;.

Изменение квалификатора на strong заставляет программу работать, но я не понимаю, как имеет смысл перейти с assign на strong. У меня сложилось впечатление, что пары для не ARC / ARC назначаются / слабые и сохраняют / сильные.

Более опытный друг-программист предположил, что, даже если квалификатор weak приводит к преждевременному освобождению window и неуспешной попытке доступа к нему, исключение должно быть EXC_BAD_ACCESS, а не EXC_BAD_INSTRUCTION.

Я, очевидно, что-то здесь упускаю, но понятия не имею, что.

РЕДАКТИРОВАТЬ: После более пристального взгляда на вывод GDB времени сбоя, тот же друг указал мне на эту статью Майка Эша , которая проливает некоторый свет на это. По независящим от меня причинам NSWindow и некоторые другие классы, которые переопределяют retain и release, не могут быть целью обнуления слабых ссылок. Интересно, что изменение объявления свойства на это работает:

@property (unsafe_unretained) IBOutlet NSWindow *window;

... хотя unsafe_unretained не упоминается в документации Apple по объявленным свойствам .

С этим ПЕРЕСМОТРЕННЫЙ ВОПРОС:

Каким будет правильный путь сюда? Придерживайтесь assign несмотря на упоминания в Интернете, что его не следует использовать с ARC? Перейти на strong? Продолжать использовать unsafe_unretained, так как он, кажется, работает? Что-то еще?

Ответы [ 3 ]

8 голосов
/ 26 октября 2011

Концептуально, «слабый» - это правильный квалификатор для IBOutlet верхнего уровня на OS X (iOS - другая история).Тем не менее, для создания надлежащей слабой ссылки, которая обнуляет освобождение, требуется взаимодействие с Objective C.Классы, которые переопределяют, сохраняют или освобождают эту поддержку, поэтому вы не можете создать слабую ссылку на них.UIWindow - один из таких классов.

Вот почему шаблон использует «assign».Возможно, он действительно должен использовать синоним unsafe_unretained, если включен ARC.В любом случае у вас есть простая слабая ссылка, которая не обнуляется.

3 голосов
/ 26 октября 2011

Блог Майка Эша обсуждает проблему с некоторыми классами Какао.

Ищите его в средней части страницы: Пятница, вопросы и ответы ARC . Посмотрите / найдите текст, который начинается с "реализации ARC обнуления слабых ссылок ..."

Проблема в том, что некоторые классы не обрабатывают обнуление слабых ссылок, которые приносит __weak. Решение состоит в том, чтобы использовать то, что обеспечивают обычные шаблоны ARC assign .

Ну, чтобы ответить на второй вопрос, даже шаблоны Apple используют assign для window при использовании ARC. Так что вы можете быть в безопасности на данный момент. Но ваш пробег может измениться в будущем.

2 голосов
/ 26 октября 2011

Майк Эш очень хорошо объясняет, что здесь происходит (поиск "реализация ARC"). Суть в том, что класс NSWindow , в частности , не поддерживает слабые ссылки: очевидно, потому что он полагается на переопределение retain и release с его собственными реализациями.

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

...