Как узнать, нужно ли мне выделять и нужно ли выпускать? - PullRequest
0 голосов
/ 25 июля 2010

Совершенно новичок в Objective-C, пытаясь выяснить, когда мне нужно выделять и освобождать объекты.

Например, я хочу получить некоторые данные из Интернета.Я нашел статью в Apple, которая имеет такой код:

NSURLRequest *theRequest=[NSURLRequest requestWithURL:
                  [NSURL URLWithString:@"http://www.apple.com/"]
                    cachePolicy:NSURLRequestUseProtocolCachePolicy
                timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] 
                                 initWithRequest:theRequest delegate:self];

Что я не понимаю, так это то, почему им нужно вызывать alloc для соединения, а не для запроса?Как узнать, когда мне нужно alloc, а когда нет?

Похожие вопросы для релиза.Из того, что я прочитал, мне нужно только выпустить объекты, которые были инициализированы с помощью alloc / init.Но все функции "initWithXXX" возвращают автоматически выпущенные объекты.

Это жесткое правило или просто соглашение?Есть ли способ узнать, нужно ли мне освобождать объект или нет?

Ответы [ 3 ]

2 голосов
/ 25 июля 2010

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

  • new
  • alloc
  • retain
  • copy

... и вам нужно только release (т.е. отказаться от владения), если вы им владеете. Если вы получаете экземпляр с помощью метода, не содержащего ни одного из них, вы не владеете им, и вам необходимо явным образом вступить во владение (используя retain), если вам это нужно.

Итак, вам нужно alloc, если вы:

  • хотите владеть или
  • , если удобного конструктора нет (и, следовательно, вам нужно использовать alloc / init)

Методы инициализатора не возвращают автоматически выпущенные экземпляры, они только инициализируют и alloc d экземпляр.

1 голос
/ 25 июля 2010

Пожалуйста, прочитайте Руководство по программированию управления памятью .Все это объясняется там.Также проверьте Learn Objective-C .


Почему им нужно вызывать alloc для соединения, а не для запроса?

Всякий раз, когда вам нужно владеть объектом, чтобы он жил дольше, чем область действия функции, объект должен быть -retain ed.Конечно, вы можете использовать

NSURLConnection* theConnection = [NSURLConnection connectionWithRequest:theRequest
                                                               delegate:self];

, но соединение будет -autorelease d.Но поскольку у соединения есть время для завершения, эта переменная должна быть -retain ed, чтобы соединение не стало недействительным.Конечно, тогда вы можете сделать

NSURLConnection* theConnection = [[NSURLConnection connectionWithRequest:theRequest
                                                               delegate:self] retain];

Но это эквивалентно +alloc-init-autorelease-retain, последние два шага излишни.Вероятно, именно поэтому Apple решает использовать +alloc / -init здесь.

(Кстати, этот стиль будет вызывать жалобы статического анализатора. Лучше хранить theConnection в виде ивара, напримеробъект делегата.)

С другой стороны, NSURLRequest - это просто временный объект, поэтому для завершения функции он должен быть -release d.Опять же, вы можете использовать

NSURLRequest* theRequest = [[NSURLRequest alloc] initWithURL:...];
...
[theRequest release];

, это еще более эффективно, так как пул автоматического выпуска не будет заполнен, но при использовании этого метода можно забыть -release и вызвать утечку.

Но все функции "initWithXXX" возвращают автоматически выпущенные объекты.

Нет, -init… никогда не должен возвращать -autorelease d объект.

1 голос
/ 25 июля 2010

initWithXXX: методы не не возвращают автоматически выпущенные объекты! somethingWithXXX: методы класса, однако, делают. Это является соглашением (в том смысле, что оно не обеспечивается компилятором), но оно соблюдается настолько близко, что вы можете рассматривать его как жесткое правило. Статический анализатор Clang также будет жаловаться, если вы не будете им следовать.

requestWithURL: не имеет имени "init" в названии. Кроме того, requestWithURL: вызывается для класса NSURLRequest, тогда как initWithRequest:delegate: вызывается для объекта NSURLConenction, возвращаемого путем вызова alloc для класса NSURLConnection.

(Я надеюсь, что все имеет смысл.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...