Введение в Objective-C
Вначале я хотел назвать этот пост “iPhone. Почему Objective-C, а не Python?” в противовес одной из моих прошлых статей “Почему Python, а не Objective-C?”, но решил что ответ на этот вопрос будет слишком коротким, а я не хочу по мелочам беспокоить читателя. По этой причине я принял решение дополнить свой комментарий на эту тему и погрузиться в основы Objective-C, попутно расширив тематику сайта. Теперь я буду освещать не только вопросы программирования на Питоне, но и затрагивать принципы создания приложений на ObjC до тех пор, пока Apple не добавит возможность создания проектов для мобильной платформы на Питоне. А может и не брошу писать на этой надстройкой над языком Си и в дальнейшем, если она придется мне по душе.
Итак, на данный момент iPhone SDK не предоставляет нам выбора каким языком воспользоваться для создания приложений, единственно доступный — Objective-C. Как вы уже поняли, ближайшая серия статей будет посвящена теме создания приложений для iPhone. Согласитесь, глупо писать о программировании под настольную Mac OS, когда буквально “вчера” повсеместно стала доступна возможность свободно писать под ее младшего брата (или сестру). И оттягивая момент знакомства с ней мы с каждым днем будем терять шансы придумать и написать приложение, которое сейчас отсутствует в AppStore, и получить свой кусок пирога. Тем более между этими двумя системами много общего: как во внутреннем устройстве, так и в используемых для создания приложений инструментах. Так что нам будет легче понять “большую” Mac OS когда дойдет очередь на страницах моего сайта затронуть вопросы создания программ под настольную ОС.
Дальнейший текст статьи основан на информации взятой из разных источников, в том числе зарубежных, местами расширеный и дополненый моими комментариями в сложных для понимания местах. Я также предполагаю, что вы знакомы с какой-либо разновидностью языка Си. В противном случае, я советую ознакомиться с информацией на эту тему в интернете, если в процессе чтения вы поймете, что начинаете “плавать” в моих объяснениях.
1. Вызов методов
Чтобы начать работу как можно быстрее, давайте рассмотрим несколько простых примеров.
Как вы уже знаете, объекты в Objective-C общаются между собой путем отправки сообщений. Базовый синтаксис вызова методов объекта следующий:
[object method];
[object methodWithInput:input];
Методы могут возвращать значения:
output = [object methodWithOutput];
output = [object methodWithInputAndOutput:input];
Вы также можете вызывать методы классов. В примере, приведенном ниже, мы вызываем метод string класса NSString, который возвращает новый объект типа NSString.
id myObject = [NSString string];
Тип id означает, что переменная myObject может ссылаться на объект любого типа. Поэтому фактический класс и методы, которые myObject предоставляет, будут неизвестны при компиляции программы. В данном примере, очевидно, тип объекта будет NSString, так что мы можем изменить код:
NSString* myString = [NSString string];
Теперь это переменная NSString, и компилятор предупредит нас, если мы попытаемся использовать методы для данного объекта, который NSString не поддерживает.
Заметьте, что справа от типа объекта стоит звездочка. Все объекты в Objective-C являются указателями типов. id является предопределенным указателем типа, поэтому не требует звездочки после своего имени (NSString — тип, NSString* — указатель типа, id — уже является указателем).
Вложенные сообщения
Во многих языках вложенные вызовы методов выглядят подобным образом:
function1 ( function2() );
Результат выполнения function2 передается в качестве параметра в function1. В Objective-C вложенные сообщения выглядят как:
[NSString stringWithFormat:[prefs format]];
Избегайте вызова вложенных сообщений на глубину более двух вложений в одной строке, поскольку вся эта конструкция легко становится нечитаемой.
Методы с параметрами
Некоторые методы могут принимать в качестве параметров несколько аргументов. В Objective-C описание метода может быть разбито на несколько сегментов. В заголовочном файле (*.h) такие методы выглядят подобным образом:
-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
Вызов их осуществляется так:
BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO];
В приведенном примере параметры являются не просто аргументами метода, а самим названием метода — writeToFile:atomically: (вспомните преобразование имен методов в PyObjC и станет куда понятней почему преобразование делалось таким странным образом )
2. Методы доступа
Все переменные экземпляров объектов в Objective-C по умолчанию объявлены как private, поэтому чтобы получать и задавать значения, в большинстве случаев, вы должны использовать методы доступа. Существует два синтаксиса.
Традиционный синтаксис
[photo setCaption:@"Day at the Beach"];
output = [photo caption];
Код во второй строке не читает значение переменной объекта напрямую. На самом деле он вызывает метод caption, который возвращает значение переменной. В большинстве случаев вам не требуется добавлять префикс get к названию метода для get-функции.
Когда вы видите код содержащийся внутри квадратных скобок — вы посылаете сообщение экземпляру объекта или классу.
Синтаксис с точкой
Синтаксис с точкой для get- и set-методов — нововведение в Objective-C 2.0, который является частью Mac OS X 10.5.
photo.caption = @"Day at the Beach";
output = photo.caption;
Вы можете использовать любой синтаксис, но придерживайтесь единого стиля в рамках одного проекта. Синтаксис с точкой может быть использован только для set- и get-методов, но не для методов общего назначения.
3. Создание объектов
Существуют два основных способа создания объектов. Первый вы видели выше:
NSString* myString = [NSString string];
Это наиболее удобный автоматизированный способ создания объектов. При таком подходе автоматически создается autoreleased объект, который мы рассмотрим детальней чуть позже. Преимущество такого подхода в том, что вам не нужно будет заботиться об освобождении памяти в конце работы программы или функции, так как это произойдет автоматически.
Однако, во многих случаях, вам может потребоваться способ создания объектов в ручном режиме:
NSString* myString = [[NSString alloc] init];
Здесь мы применили вложенный способ для создания объекта. Первый метод alloc является методом класса NSString. Это сравнительно низкоуровневый метод, которые выделяет память, связывает ее с объектом и возвращает указатель на нее.
Второй метод init является уже методом созданного экземпляра объекта. Init, как правило, делает основные настройки, такие как инициализацию переменных.
В некоторых случаях вы можете использовать различные версии init, которые принимает параметры инициализации:
NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];
Обратите внимание, что init является обычным методом, а не конструктором. Довольно часто у объектов бывает сразу несколько методов, начинающихся с init, например init, initWithName, initWithContentsOfFile и т.д. Установившейся практикой в таком случае является выделение среди всех init-методов одного, называемого designated initializer. Все остальные init-методы должны вызывать его и только он вызывает унаследованный init метод.
— initWithName: (const char *) theName // designated initializer
{
[super init]; // вызов родительского метода
name = strdup ( theName );
}
— init
{
return [self initWithName: ""];
}
4. Управление памятью
В процессе создания приложения для Mac OS у вас есть возможность включить систему сборки мусора (garbage collector). В общем, это означает, что вам не придется думать об управлении памятью, пока вы не доберетесь до более сложных случаев.
Однако, вы не всегда сможете работать в окружении, которое поддерживает автоматическую сборку мусора. В этом случае, вам необходимо знать несколько основных понятий.
Если вы создаете объект, через вызов alloc, вам необходимо будет уничтожить его и освободить память при выходе из программы или в конце участка кода, использующего данный объект, вызовом функции release. Вы не должны вручную уничтожать autoreleased объекты, это будет ошибкой.
Вот два примера:
// string1 будет удалена сборщиком мусора в автоматическом режиме
NSString* string1 = [NSString string];
// для string2 вы должны будете вручную вызвать release метод
NSString* string2 = [[NSString alloc] init];
[string2 release];
Выяснить какие методы поддерживают autorelease, а какие нет очень легко. Откройте список методов инициализации для выбранного класса. Возьмем, например, NSString. Пролистайте страницу до раздела “Creating and Initializing Strings”. Все методы, отмеченные плюсом в начале имени являются методами класса и вызываются для создания строк как в нашем первом примере. Для них проводить вызов release не нужно. Все остальные методы инициализации, почеменные знаком минус перед именем, являются методами экземпляров объектов и могут быть вызваны только после создания объекта, т.е. вызова метода alloc, как в нашем втором примере.
5. Проектирование интерфейса класса
Синтаксис Objective-C для описания классов очень прост. Как правило, класс состоит из двух файлов.
Интерфейс класса хранится в ClassName.h файле, и описывает переменные и public методы.
Реализация класса — ClassName.m файл, содержащий фактический код для этих методов. Он также часто определяет частные методы, которые не доступны вне класса или экземпляра класса.
Файл интерфейса выглядит следующим образом:
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
@end
Во-первых, мы импортируем Cocoa.h, чтобы получить доступ ко всем основным классам библиотеки Cocoa. Директива #import аналигична include в Си, но гарантирует что данный файл будет подключен всего один раз.
@interface описывает класс Photo, унаследованный от NSObject, который является прародителем всех классов в Objective-C.
Внутри фигурных скобок описаны две переменные экземпляров: caption и photographer, обе типа NSString.
И наконец, @end обозначает окончание описания класса.
Добавляем методы
Давайте добавим get-методы для наших переменных.
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
— caption;
— photographer;
@end
Запомните, get-методы в Objective-C, как правило, опускают префикс “get” в своем имени. Минус перед названием метода показывает, что это метод экземпляра объекта. Плюс перед именем означает, что это метод класса.
По умолчанию компилятор полагает что метод возвращает переменную типа id, и все параметры вызова функций тоже являются переменными данного типа. Код указанный выше технически является правильным, но выглядит необычно.
Давайте явно укажем типы возвращаемых значений.
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
— (NSString*) caption;
— (NSString*) photographer;
@end
А теперь давайте добавим set-методы.
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
— (NSString*) caption;
— (NSString*) photographer;
— (void) setCaption: (NSString*)input;
— (void) setPhotographer: (NSString*)input;
@end
Set-методы не возвращают значений, поэтому мы определяем их как void.
6. Реализация класса
Давайте напишем реализацию класса, начнем с get-методов.
#import "Photo.h"
@implementation Photo
— (NSString*) caption {
return caption;
}
— (NSString*) photographer {
return photographer;
}
@end
Эта часть кода начинается с директивы @implementation и имени класса, и заканчивается директивой @end, между которыми заключена реализация нашего класса.
Реализация get-методов должна быть очень вам знакома, если вы когда-либо писали реализацию подобного кода. Давайте перейдем к set-методам, который требуют более детального объяснения принципов своей работы.
— (void) setCaption: (NSString*)input {
[caption autorelease];
caption = [input retain];
}
— (void) setPhotographer: (NSString*)input {
[photographer autorelease];
photographer = [input retain];
}
Каждый set-метод оперирует двумя переменными. Первая — ссылка на существующий объект, вторая является новым значением. В случае использования сборщика мусора мы могли непосредственно установить новое значение:
— (void) setCaption: (NSString*)input {
caption = input;
}
Но если вы не можете использовать сборщик мусора, то должны вначале удалить ссылку на старый объект, а затем получить ссылку на новый.
Существует два способа освобождения объекта: release и autorelease. Стандартный release удалит ссылку на объект незамедлительно. Autorelease сделает это чуть позже, и ссылка на объект будет оставаться действительной до выхода из функции, где autorelease был вызван.
Использование autorelease безопаснее использовать в set-методах, так как переменные для нового и старого значения могут указывать на один и тот же объект. А вы бы не хотели немедленно освободить объект, который собираетесь использовать.
Метод retain возвращает ссылку на объект и увеличивает количество ссылок во внутреннем счетчике для переменной input на единицу (подробней о подсчете ссылок в следующей части). С каждым вызовом метода release количество ссылок на объект наоборот уменьшается на единицу. Когда оно достигает нуля, метод release вызывает dealloc, где объект удаляется и память освобождается.
Init
Мы можем написать метод init для инициализации переменных значениями по умолчанию.
— (id) init {
if ( self = [super init] ) {
[self setCaption:@"Default Caption"];
[self setPhotographer:@"Default Photographer"];
}
return self;
}
Код выглядит достаточно понятным, разве что кроме второй строки. Здесь происходит присвоение переменной self значения вызова инициализатора унаследованного класса, в нашем случае класс NSObject. В условии if идет проверка, что инициализация прошла успешно, прежде чем приступить к присвоению нашим переменным значений.
Dealloc
Этот метод вызывается для объекта, когда последний будет удален из памяти. Можно сказать, аналог деструктора. В реализации этого метода самое время удалить ссылки на объекты всех переменных.
— (void) dealloc {
[caption release];
[photographer release];
[super dealloc];
}
В первых двух строках мы просто вызываем release для каждой из наших переменных. В этом методе нет необходимости вызывать autorelease, вызов обычного release будет немного быстрее.
Последняя строка имеет очень большое значение. Мы должны послать сообщение [super dealloc] унаследованному объекту, чтобы удаление прошло корректно. Если мы забудем это сделать, то это приведет к утечкам памяти.
Метод dealloc не вызывается, если вы используете сборщик мусора. Вместо него вам следует написать реализацию метода finalize.
7. Еще несколько слов об управлении памятью
Система управления памятью в Objective-C основана на подсчете ссылок. Все что вам нужно делать — следить ссылками, среда выполнения сама осуществит освобождение памяти.
Выражаясь простым языком, вызываете ли вы alloc, или retain сколько бы то ни было раз, то для корректного удаления объекта вы должны вызвать такое же число раз метод release.
Существуют две причины для использования объектов в программе:
- Для использования его как переменной экземпляра
- Для единоразового использования внутри функции
В большинстве случаев, set-методы должны вызвать autorelease для старого, и retain для нового объекта. Затем просто убедитесь, что не забыли вызвать release в dealloc для ваших переменных экземпляров.
Так что единственная реальная работа по управлению ссылками происходит внутри вызова функции. И здесь действует лишь одно правило: если вы создаете объект при помощи alloc или copy, не забудьте отправить ему release или autorelease сообщение в конце функции. Если вы создаете объект другими способами, то не делайте ничего.
Ниже представлен пример реализации первого варианта.
— (void) setTotalAmount: (NSNumber*)input {
[totalAmount autorelease];
totalAmount = [input retain];
}
— (void) dealloc {
[totalAmount release];
[super dealloc];
}
Вот другой случай, с локальными переменными.
NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
NSNumber* value2 = [NSNumber numberWithFloat:14.78];
// освобождаем value1, но не value2
[value1 release];
А вот комбинация: используем локальные переменные, чтобы задать значения переменным экземпляра.
NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
[self setTotal:value1];
NSNumber* value2 = [NSNumber numberWithFloat:14.78];
[self setTotal:value2];
[value1 release];
Заметьте, что правила для локальных переменных те же самые, что и для переменных экземпляра.
Если вы поймете эту главу, то вы поймете 90% из того, что вам понадобится знать об управлении памятью в Objective-C.
8. Ведение логов событий
Процесс записи сообщений в лог (консоль) в Objective-C очень прост. Фактически, синтаксис функции NSLog() идентичен функции printf() в языке C, за исключением использования дополнительного ключа %@ для объектов.
NSLog ( @"The current date and time is: %@", [NSDate date] );
Для объектов, NSLog производит вызов метода description объекта и выводит результат в лог. Вы можете переопределить метод description в реализации своего класса, чтобы возвращать свои сообщения.
9. Свойства
Когда мы писали методы доступа для caption и photographer, вы могли заметить, что код достаточно прост и его можно было бы обобщить.
Свойства в Objective-C дают нам возможность автоматически создавать методы доступа к переменным, и кроме того, имеют другие выгоды для нас. Давайте изменим класс Photo, чтобы он использовал свойства.
Наш старый код:
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
— (NSString*) caption;
— (NSString*) photographer;
— (void) setCaption: (NSString*)input;
— (void) setPhotographer: (NSString*)input;
@end
Код после использования свойств:
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
@property (retain) NSString* caption;
@property (retain) NSString* photographer;
@end
Директива @property как раз и определяет свойство объекта. “retain” в скобках означает, что реализующий это свойство set-метод должен получать новое значение отправкой сообщений retain.
Давайте взглянем на реализацию нашего класса:
#import "Photo.h"
@implementation Photo
@synthesize caption;
@synthesize photographer;
— (void) dealloc {
[caption release];
[photographer release];
[super dealloc];
}
@end
Директива @synthesize автоматически генерирует set- и get-методы для нас, так что единственное что мы должны реализовать в этом классе — метод dealloc.
Методы доступа будут сгенерированы только в том случае, если они не были реализованы ранее. Так что используйте @synthesize безбоязненно и пишите свои собственные реализации методов доступа — компилятор сам сгенерирует недостающие методы.
10. Использование пустого указателя в вызове методов
В Objective-C объект nil эквивалентен NULL указателю во многих других языках. Разница в том, что вы можете вызывать функции, используя nil без боязни вызвать exception.
Этот способ используется во многих фреймворках для достижения различных целей, но главное преимущество в том, что отпадает необходимость проверки на nil перед вызовом метода.
Мы можем использовать этот способ, чтобы немного улучшить наш dealloc метод:
— (void) dealloc {
self.caption = nil;
self.photographer = nil;
[super dealloc];
}
Приведенный код работает потому, что set-метод вызывает retain для nil (который ничего не делает) и освобождает старое значение. Такой подход зачастую лучше для dealloc метода потому, что не оставляет шансов указателям переменных класса указывать на случайный участок в памяти после вызова release. Представьте, что после вызова release в dealloc по глупости обратитесь к освобожденной переменной. Что будет лучше: чтобы она укзывала на случайный участок в памяти или была значением nil?
Заметьте, что мы используем синтаксис с self. в приведенном выше примере, что означает мы используем set-методы дабы избежать проблем с освобождением памяти от старого значения наших переменных. Если мы произведем присвоение напрямую, то вызовем утечку памяти:
// Неверно! Вызывает утечку памяти
caption = nil;
11. Категории
Категории являются одним из наиболее полезных возможностей Objective-C. По сути, категории позволяют добавлять методы к существующим класса без наследования и без знаний каких-либо подробности того, как класс реализован. Особенно полезно то, что вы можете добавить дополнительные методы для встроенных объектов. Если вы хотите добавить метод для всех экземпляров объекта NSString в вашем приложении, просто добавьте категорию. Это намного проще, чем наследовать и создавать подкласс от NSString.
Например, если вы хотите добавить метод в NSString, который определяет является ли строка корректно составленным URL-адресом, реализация интерфейса будет выглядеть следующим образом:
#import <Cocoa/Cocoa.h>
@interface NSString (Utilities)
— (BOOL) isURL;
@end
Это очень похоже на объявление класса. Разница в том, что отсутсвует указание родительского класса, а в скобках указано имя категории, которое вы можете выбрать абсолютно произвольно.
Ниже пример простейшей реализации:
#import "NSString-Utilities.h"
@implementation NSString (Utilities)
— (BOOL) isURL {
if ( [self hasPrefix:@"http://"] )
return YES;
else
return NO;
}
@end
Теперь вы можете использовать метод isURL в любых объектах NSString. Следующий пример выведет в консоль “string1 это URL”.
NSString* string1 = @"http://apple.com/";
NSString* string2 = @"Apple";
if ( [string1 isURL] )
NSLog (@"string1 это URL");
if ( [string2 isURL] )
NSLog (@"string2 это URL")
В отличие от наследования, категории не могут добавлять новые переменные в класс. Однако, вы можете переопределять существующие методы в классе, но должны быть очень осторожны.
Запомните, что все изменения сделанные в классе через категории повлияют на все экземпляры данного объекта в программе.
Дополнительная информация:
Рекомендую дополнительно к данному материалу почитать описание Objective-C в Википедии и воспользоваться ссылками, указанными в конце статьи.
Комментарии
Есть ещё такой момент, что насколько я понимаю, приложения, использующие синтаксис с точкой, хотя он и более удобен на мой взгляд, не будут работать на MacOS версии младше, чем Leopard, т.к. их ObjectiveC runtime его не поддерживает.
Совершенно верно. Сборщик мусора, свойства и некоторые другие нововведения были добавлены в Objective-C 2.0, пришедший с Mac OS X 10.5 и не будут работать на версии ОС ниже данной. Что и говорить про iPhone SDK, который вобще не будет работать на версиях ниже 10.5.3.
ИМХО зря они добавили точку. Как теперь сходу отличить класс от простой струкутры? раньше все было понятно.
И к тому же, кода через точку идет присвоение, то на самом деле это не простое присвоение, а вызов функции. Зачем вводить новичков в заблуждение?
Спасибо, очень актуально. Посоветуйте, что ещё почитать на тему. Ну кроме http://developer.apple.com/iphone/ конечно ;)
На самом деле, наиболее полного материала, чем вот в этой документации не найти: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf Действительно, очень полное и подробное описание, единственный минус — на английском, если это имеет значение для тебя :)
На русском же языке материала практически нет. Единственное, можно почитать статью в Википедии, ссылку на которую я привел в посте. Статья хорошая для понимания и раскрывает концепции, которые я не описал здесь, дабы не копипастить, что делать не люблю.
Я уже перевожу кое-что :) Может и за ObjC.pdf возьмусь…
В данном случае: @property (retain) NSString* caption;
Как бы явно видно, что перед тем, как объект будет отдан “во вне” (через obj.caption), автоматически инкрементируеться его счетчик ссылок. Кто в данном случае должен релизить объект?
Как я понимаю если NSString был создан как NSString *str = [NString string], то release будет автоматическим, а если через alloc то нужно release вызывать самостоятельно?
Форма комментирования для «Введение в Objective-C»
чет я ниче не понял. setter будет такой:
-(void) setCaption:(NSString*)NewCaption {
if (caption != NewCaption) {
[caption release];
caption = [NewCaption retail];
}
все происходит как и положено, в чем проблемы?
Я не о сеттере. Допустим есть у нас какой-то наш класс OurContainer (его инстанс container) у него есть свойство к примеру ourString, которое возвращает NSString и автоматически ее ретайнит. Если мы делаем
NSString *str = container.ourString;
Произошел автоматом ретайн. Кто должен делать release для str, если: 1. Работает сборщик муссора. 2. Не работает сборщик муссора.
При таком присвоении retain не выполняется. Собственно, я описал ниже как все происходит.
Вопрос в догонку: caption != NewCaption
Это я надеюсь сравнение указателей, а не содержимого строк?
Счетчик ссылок при отдаче в самом get-методе нашего объекта увеличиваться не будет, операция retain будет произведена в принимающем значение объекте. Допустим:
1) изначально мы присвоили obj.caption = @”some text”; Строк, инициализованная директивой @”“, как я писал в своей более поздней статье, создает строку-константу в памяти. После присвоения этой строки нашему свойству, количество ссылок на нее увеличивается и становится равной 1
2) Если мы присваиваем значение caption нашего объекта другой переменной, например, следующим образом:
NSString *str = [[NSString alloc] initWithString:obj.caption];
то объект obj просто отдает в своем get-методе ссылку на значение, без совершения опреации retain, которая на самом деле происходит в методе initWithString. Таким образом, после выполнения данного присваивания на нашу строку в памяти будут ссылаться два объекта и потребуется 2 раза вызвать release, чтобы не вызвать утечек: один раз после окончания использования str, второй в деструкторе объекта dealloc.
Как ретайнятся объекты в alloc/dealloc я понял, очень похожий метод применяется в IOKit (на котором я собаку сьел) для С++.
ОК, я понял, рейтайнить объект должен тот, кто вызывает геттер, после того, как геттер отработает. Вроде бы все проясняется %)
Отличная статья. Спасибо за инфо. Решил заняться программингом под iPhone, на русском действительно нет почти инфо. Желаю успехов и так держать! ))
ДОбавил в гуглоридер.
продолжайте в том же духе Ваши статьи нужны программерам
Спасибо. Вижу вы регулярно обновляете блог статьями – что в двойне достойно уважения =)
Правильно ли я понимаю, метод класса, создающий экземпляр данного класса, должен выглядеть примерно так:
+(MyObj )objWithDate:(NSDate )anyDate andValue:(float)anyValue {
}
Вопрос в autorelease. К месту ли он здесь стоит, и что в таком случае произойдет, когда созданный при помощи такого метода объект ”умрет”?
Отцы, объясните мне, дураку, ну чем Obj-C так “крайне прост” и в чём выражается эта хвалёная “концепция software IC”, которая, якобы, позволяет “собирать программы из готовых компонент”? Ну не вижу я в упор никаких преимуществ! Разве только то что “на данный момент iPhone SDK не предоставляет нам выбора каким языком воспользоваться”, так это ещё не означает что язык так крут как его описывают.
Вы батенька неправы. Да-с. Если-бы Mac OS Х(Cocoa) разжился-бы бесплатным C/C++, то каждбый чудак на букву “М” мог-бы клепать код под креативы Apple. А так — хрен вам. Учите новый язык и новую матчасть. А не хотите — покупайте компилятор Intel-а за $400. Но учтите, он будет фурычить только на процессорах тов. Оттолини. Вот все материли Билла Г. за Windows и .NET и C#, не говоря уже о бредовом Managed C++-е (бедняга даже уволился из фирмы из-за критики), а он в последней студии C++ оставил и даже творчески развил в соответствие со стандартом. Человеком с большой Б(буквы) оказался, не то, что спятивший Джобс. Понятно, когда буржуй получает $1 в год, он с зависти беситься начинает и изобретать всякую хрень, что-б только народу нагадить. Вот и тут так. Учите Карлсона и Энгельсона. Они это ещё 150 лет назад знали.
Вы написали про управление памятью следующее:
// string1 будет удалена сборщиком мусора в автоматическом режиме NSString string1 = [NSString string]; // для string2 вы должны будете вручную вызвать release метод NSString string2 = [[NSString alloc] init]; [string2 release];
Вопрос. А если NSString* ссылается на константу, следует ли освобождать память руками? Пример: NSString baseDescription = [super description]; а в суперклассе description таков: -(NSString) description { return @”SOME STRING”; }
Я так полагаю, что освобождать память в данном случае не требуется руками. Тогда подскажите, как лучше организовать код для исключения ошибок типа утечки памяти, двойного освобождения памяти и т. п.? Дело в том, что я пришел к Objective-C из мира .NET и Java, поэтому не имею практики написания грамотного Си кода…
“Реализация класса — ClassName.m файл, содержащий фактический код для этих методов. Он также часто определяет частные методы, которые не доступны вне класса или экземпляра класса.” Нету там недоступных методы. Все методы одинаково доступны — посылай сообщение и он прекрасно выполнится. В objC нету private и protected методов.
не совсем,
можно сделать “private” сообщения – в .m-файле написать до @implementation
@interface MyClass() // <= пустые скобки!! — (void)doSomething; @end
@implementation MyClass //реализация всего, включая doSomething @end
то затем при вызове внутри класса MyClass, например [self doSomething]; все будет работать, но при вызове этого метода извне, будет бросаться исключение undefined selector.
Скажите, а переменная self — это аналог this в С++?
да, это примерно тоже самое. Разница есть, но не на поверхностном уровне