Objective-C для программистов C++. Часть 3
Перевод серии статей David Chisnall «Objective-C for C++ Programmers»
http://netsago.org/ru/docs/1/15/
Objective-C был спроектирован как минимальный набор расширений для C, предоставляющих семантику, схожую со Smalltalk. Он также включает в себя схожий со Smalltalk синтаксис, с помощью которого проще увидеть, какая часть кода является чистым C, а какая — содержит расширения Objective-C.
Интроспекция
В C++ есть некоторая поддержка интроспекции с помощью Runtime Type Information (RTTI). Обычно её плохо поддерживают компиляторы, а там, где такая поддержка есть, она редко используется «в целях производительности». В противоположность этому, интроспекция всегда доступна в Objective-C.
Обычно структура класса содержит один связанный список или массив метаданных о методах и другой — для переменных экземпляра. Для каждой переменной экземпляра он включает в себя смещение с начала объекта, тип и имя. Вы можете использовать это для создания довольно интересных вещей. Например, я написал фреймворк для Étoilé, который проверяет эту информацию и использует её для автоматического размножения объектов (в C++ это возможно только для тех объектов, исходный код для которых у вас есть). Для методов там есть имя, тип и указатель на функцию, реализующую метод. Это называется Instance Method Pointer (IMP) и определено в заголовочном файле следующим образом:
Он использует два других типа Objective-C. Тип id — указатель на объект некоторого вида. Все, что вы знаете про id это то, что он будет отвечать на сообщения (не смотря на то, что вы не знаете, какие сообщения, пока не спросите). Другой — SEL — тип селектора.
Вы можете сделать следующее:
Переменная method теперь указатель на функцию C, указывающий на реализацию метода. Если вы посылаете такое же сообщение объекту, вы можете использовать эту возможность для повышения скорости.
Так как вы можете строить селекторы в рантайме, вы сможете использовать этот подход для некоторого очень динамичного окружения. В парсере XML в Étoilé я использовал это когда добавлял дочерние элементы в объект, представляющий собой элемент XML. Корневой класс реализует метод -addChild:forKey:, содержащий следующий код:
Он создает селектор из ключевого имени, а затем вызывает его с объектом. Этот подход использован во многих местах в реализации XMPP. Например, тег может быть пропарсен классом, который просто собирает символьные данные и превращает их в строку. Когда он достигает , он делает примерно следующее:
Затем родитель вызывает этот метод, который производит вызов его метода -addname: со строкой в качестве аргумента. Более сложная форма находится в Cocoa в форме KVC, где проводится интроспекция и метода и метаданных переменой экземпляра. Когда вы вызываете -setValue:forKey:, производится вызов установщика, устанавливающего переменную экземпляра напрямую или вызов -setValue:forUndefinedKey:. Использование KVC медленнее, чем установка переменных экземпляра напрямую или даже прямой вызов методов set/get, но он полностью изолирует реализацию от интерфейса.
В Objective-C 2.0 Apple предоставила свойства, доступ к которым происходит следующим образом:
Это очень тонкий слой синтаксического сахара. Внутри они переводятся в сообщения set и get, в зависимости от того, какое свойство было использовано. Лучшей возможностью свойств является то, что они позволяют этим методам set и get генерироваться автоматически для любой переменной экземпляра с семантикой удержания в памяти, присваивания или копирования.
Протоколы
В Objective-C протоколами являются наборы сообщений, реализующих класс. Вы можете указать, что указатель должен указывать на класс, реализующий данный интерфейс:
Первый пример эквивалентен объявлению переменной, как тип интерфейса в Java. В C++ ближайшим эквивалентом является использование абстрактных классов вместо интерфейсов и указание абстрактного класса в качестве типа.
Более интересен второй пример. Строковой переменной дозволено быть любым подклассом NSString, который реализует AnInterface, который позволяет вам ограничивать подмножество подклассов, реализующий отдельный интерфейс. Общий пример:
Это позволяет ему быть любым подклассом NSObject (и поэтому методы, которые вы ожидаете от любого объекта, будут работать) и дополнительно требуется реализовать определенный протокол. А вот альтернативный вариант:
Это работает для NSObject, так как NSObject является и классом, и протоколом, с классом, перенимающим протокол. Это было сделано так, чтобы NSProxy и другие корневые классы могли быть использованы поочередно с подклассами NSObject.
Так как Objective-C произошел от Smalltalk с принципом «всё является объектом», неудивительно, что протоколы, как и классы, тоже объекты. Вы можете посылать им сообщения для проведения интроспекции. Обычно вы не делаете это сами, вместо чего полагаясь на сообщения, посланные к подклассам NSObject:
Вещью, которая немного смущает в протоколах, является тот факт, что они проверяются на равенство простым сравнением имен. Если у вас есть два протокола с одинаковыми именами, то у вас нет способа указать в рантайме, который из них реализует объект. Причиной этому послужило разрешение проверки для согласования с помощью директивы @protocol(), как продемонстрировано выше, в исходных файлах, у которых нет доступа к описанию протокола; но это может вызвать неразбериху.
Расширенные классы
Одной из вещей, прямых аналогов которой нет в C++, является идея категории — коллекции методов, которые добавляются к существующему классу. Будучи загруженной, категория не имеет отличий от других методов. Категории, как и классы, объявляются с интерфейсом и реализацией.
Интерфейсы категории могут быть использованы без соответствующей реализации для раскрытия других методов, предоставляя нечто похожее на дружественные функции в C++. Если вы реализуете методы в классе, но не объявляете их в интерфейсе, вы получите предупреждение при компиляции в тех местах, где вы используете их. Вы можете сделать такой интерфейс категории:
Если вы поместите это в начало файла реализации, вы не получите предупреждения во время компиляции, когда отправите сообщение -privateMethod экземплярам AnObject. Имя в скобках (Private) — просто имя категории. Оно может быть любым. Обратите внимание на то, что без раздела @inmplementation, это просто станет ранним объявлением C функции. Если нет соответствующей реализации в C, вы получите ошибку линковщика. Если нет соответствующей реализации метода в Objective-C, вы получите исключение в рантайме.
Вы можете предоставить дополнительную реализацию метода, используя категорию точно таким же путем, как и когда вы предоставляли «нормальные» методы:
Если вы отправите сообщение -newMethod любому экземпляру AnObject, этот метод будет вызван. Вы также можете использовать это для замены существующих методов в объекте на свою собственную версию, поэтому вам не нужен доступ к объекту. Этот подход часто используется для дополнения различных методов библиотечных классов дополнительным функционалом, а также может быть использован для исправления багов в сторонних библиотеках, исходных кодов которых у вас нет.
Менее документированной частью категорий является то, что категории позволяют вам добавлять соответствия протоколов к существующим объектам. Если ваша категория перенимает протокол, вы получите предупреждение во время компиляции, если вы не предоставляете реализаций каждого метода, и станет возможным провести тесты во время исполнения программы для проверки соответствия. Мы использовали эту возможность в Étoilé для добавления соответствия коллекции протоколов ко всей коллекции классов в Foundation, дав им совместимый интерфейс.
Неформальные протоколы
Очень частым шаблоном в Objective-C является идея неформального протокола, — коллекции методов, которые класс может реализовывать, а может не реализовывать. Её частое использование — для делегирования объектов. В Java очень часто для делегатов ожидается реализация интерфейса. У такого подхода часто есть набор методов, некоторые из которых реализованы как методы без тела.
В Objective-C сть два пути для определения неформальных протоколов. Первый — определение категории на базовом классе (обычно на NSObject), которая предоставляет нулевые реализации каждого метода. Это означает, что каждый класс будет отвечать на сообщения в интерфейсе, но что-то действительно делать будут только реализованные методы. Вы должны поместить в файл исходного кода, который использует неформальный протокол, нечто следующее:
Затем вы просто отправляете сообщение handleSomethingFrom: делегированному объекту. Обратите внимание, что вам не нужен раздел @interface для создания разделения между интерфейсом и реализацией для категорий; интерфейс приватен, а вам не нужно, чтобы что-то ещё вызывало этот метод, кроме вашего класса, поэтому не открывайте интерфейс. Хотя этот метод прост, он не идеален во многих случаях, так как приводит к заполнению координирующей таблицы корневого объекта в основном не используемым хламом (который может привести к понижению производительности в рантайм Apple из-за того, как там реализовано кеширование).
Другой вариант — производить тестирование в рантайме. Если вы пошлете объекту сообщение respondsToSelector:, вы можете выяснить, реализует ли он названный метод. Для делегатов, вы можете затем кешировать IMP для метода, и вызвать его напрямую позже. В вашем методе setDelegate: будет нечто такое:
Потом при использовании, вы делаете следующее:
Objective-C 2.0 дает третий вариант, который предназначен для использования директивы @optional в объявлении протокола. Это большая трата памяти, так как вам необходимо производить тесты в рантайме для определения, реализует ли объект, сопоставленный протоколу, опциональный метод из этого протокола.
Повторная отправка
В C++ вы не посылаете сообщения, а вызываете функции-члены. Это важное отличие, так как оно обозначает, что вызываемые методы семантически схожи с вызовом функций. Objective-C вносит другой слой абстракции. Если вы посылаете сообщение объекту Objective-C, который его не понимает, возникнет исключение. Тем не менее, это не делается самим языком.
Библиотека рантайма имеет механизм устранения неисправностей, когда нет метода для селектора. Она вызывает метод, который интроспектирует получателя для некоторой информации о типе, помещает вызов в объект NSInvocation, а затем передает его методу -forwardInvocation: данного объекта.
Объект NSInvocation инкапсулирует получателя, селектор и аргументы. Вы можете использовать эту идею для отправки сообщений высокого порядка. Рассмотрим следующий пример:
Метод -map, примененный к массиву, возвращает объект прокси с помощью метода forwardInvocation:, реализованного подобным образом:
FOREACHI — макрос из Étoilé, который просто производит кеширование IMP на NSEnumerator. Когда вы посылаете сообщение -toUppercase к мэп прокси, он производит итерацию по каждому объекту массива; проверяет, отвечает ли он селектору и, если да, вызывает метод с аргументами. Возвращаемое значение добавляется к новому массиву.
Это почти невозможно сделать в C++. Вы можете использовать шаблон команды, чтобы сделать нечто похожее, но только реализовав сначала ваш собственный механизм диспетчеризации.
Заключение
Objective-C очень небольшой язык и мы рассмотрели практически все в этой серии статей, включая некоторые продвинутые возможности. Тем не менее, как и в Smalltalk, он несколько вводит в заблуждение. В то время как ядро языка очень просто, большинство из окружения программ на Objective-C приходит из библиотеки. Обычно это реализация спецификации OpenStep, такие как GNUstep или Cocoa от Apple, а знакомство с библиотекой может занять много времени.
http://netsago.org/ru/docs/1/15/
Objective-C был спроектирован как минимальный набор расширений для C, предоставляющих семантику, схожую со Smalltalk. Он также включает в себя схожий со Smalltalk синтаксис, с помощью которого проще увидеть, какая часть кода является чистым C, а какая — содержит расширения Objective-C.
Интроспекция
В C++ есть некоторая поддержка интроспекции с помощью Runtime Type Information (RTTI). Обычно её плохо поддерживают компиляторы, а там, где такая поддержка есть, она редко используется «в целях производительности». В противоположность этому, интроспекция всегда доступна в Objective-C.
Обычно структура класса содержит один связанный список или массив метаданных о методах и другой — для переменных экземпляра. Для каждой переменной экземпляра он включает в себя смещение с начала объекта, тип и имя. Вы можете использовать это для создания довольно интересных вещей. Например, я написал фреймворк для Étoilé, который проверяет эту информацию и использует её для автоматического размножения объектов (в C++ это возможно только для тех объектов, исходный код для которых у вас есть). Для методов там есть имя, тип и указатель на функцию, реализующую метод. Это называется Instance Method Pointer (IMP) и определено в заголовочном файле следующим образом:
typedef id (*IMP)(id, SEL, ...);
Он использует два других типа Objective-C. Тип id — указатель на объект некоторого вида. Все, что вы знаете про id это то, что он будет отвечать на сообщения (не смотря на то, что вы не знаете, какие сообщения, пока не спросите). Другой — SEL — тип селектора.
Вы можете сделать следующее:
IMP method = [object methodForSelector:@selector(doSomething)];
Переменная method теперь указатель на функцию C, указывающий на реализацию метода. Если вы посылаете такое же сообщение объекту, вы можете использовать эту возможность для повышения скорости.
Так как вы можете строить селекторы в рантайме, вы сможете использовать этот подход для некоторого очень динамичного окружения. В парсере XML в Étoilé я использовал это когда добавлял дочерние элементы в объект, представляющий собой элемент XML. Корневой класс реализует метод -addChild:forKey:, содержащий следующий код:
NSString * childSelectorName =\
[NSString stringWithFormat:@"add%@:", aKey];
SEL childSelector = NSSelectorFromString(childSelectorName);
if([self respondsToSelector:childSelector])
{
[self performSelector:childSelector withObject:aChild];
}
[NSString stringWithFormat:@"add%@:", aKey];
SEL childSelector = NSSelectorFromString(childSelectorName);
if([self respondsToSelector:childSelector])
{
[self performSelector:childSelector withObject:aChild];
}
Он создает селектор из ключевого имени, а затем вызывает его с объектом. Этот подход использован во многих местах в реализации XMPP. Например, тег может быть пропарсен классом, который просто собирает символьные данные и превращает их в строку. Когда он достигает , он делает примерно следующее:
[parent addChild:string forKey:@"name"];
Затем родитель вызывает этот метод, который производит вызов его метода -addname: со строкой в качестве аргумента. Более сложная форма находится в Cocoa в форме KVC, где проводится интроспекция и метода и метаданных переменой экземпляра. Когда вы вызываете -setValue:forKey:, производится вызов установщика, устанавливающего переменную экземпляра напрямую или вызов -setValue:forUndefinedKey:. Использование KVC медленнее, чем установка переменных экземпляра напрямую или даже прямой вызов методов set/get, но он полностью изолирует реализацию от интерфейса.
В Objective-C 2.0 Apple предоставила свойства, доступ к которым происходит следующим образом:
object.property = 12;
Это очень тонкий слой синтаксического сахара. Внутри они переводятся в сообщения set и get, в зависимости от того, какое свойство было использовано. Лучшей возможностью свойств является то, что они позволяют этим методам set и get генерироваться автоматически для любой переменной экземпляра с семантикой удержания в памяти, присваивания или копирования.
Протоколы
В Objective-C протоколами являются наборы сообщений, реализующих класс. Вы можете указать, что указатель должен указывать на класс, реализующий данный интерфейс:
id<AnInterface> object;
NSString<AnInterface> *string;
NSString<AnInterface> *string;
Первый пример эквивалентен объявлению переменной, как тип интерфейса в Java. В C++ ближайшим эквивалентом является использование абстрактных классов вместо интерфейсов и указание абстрактного класса в качестве типа.
Более интересен второй пример. Строковой переменной дозволено быть любым подклассом NSString, который реализует AnInterface, который позволяет вам ограничивать подмножество подклассов, реализующий отдельный интерфейс. Общий пример:
NSObject<MyDelegateProtocol> *delegate;
Это позволяет ему быть любым подклассом NSObject (и поэтому методы, которые вы ожидаете от любого объекта, будут работать) и дополнительно требуется реализовать определенный протокол. А вот альтернативный вариант:
id <NSObject, MyDelegateProtocol> delegate;
Это работает для NSObject, так как NSObject является и классом, и протоколом, с классом, перенимающим протокол. Это было сделано так, чтобы NSProxy и другие корневые классы могли быть использованы поочередно с подклассами NSObject.
Так как Objective-C произошел от Smalltalk с принципом «всё является объектом», неудивительно, что протоколы, как и классы, тоже объекты. Вы можете посылать им сообщения для проведения интроспекции. Обычно вы не делаете это сами, вместо чего полагаясь на сообщения, посланные к подклассам NSObject:
if ([object conformsToProtocol:@protocol(MyDelegateProtocol)])
{
// Действия с делегированным протоколом
}
{
// Действия с делегированным протоколом
}
Вещью, которая немного смущает в протоколах, является тот факт, что они проверяются на равенство простым сравнением имен. Если у вас есть два протокола с одинаковыми именами, то у вас нет способа указать в рантайме, который из них реализует объект. Причиной этому послужило разрешение проверки для согласования с помощью директивы @protocol(), как продемонстрировано выше, в исходных файлах, у которых нет доступа к описанию протокола; но это может вызвать неразбериху.
Расширенные классы
Одной из вещей, прямых аналогов которой нет в C++, является идея категории — коллекции методов, которые добавляются к существующему классу. Будучи загруженной, категория не имеет отличий от других методов. Категории, как и классы, объявляются с интерфейсом и реализацией.
Интерфейсы категории могут быть использованы без соответствующей реализации для раскрытия других методов, предоставляя нечто похожее на дружественные функции в C++. Если вы реализуете методы в классе, но не объявляете их в интерфейсе, вы получите предупреждение при компиляции в тех местах, где вы используете их. Вы можете сделать такой интерфейс категории:
@interface AnObject (Private)
- (void) privateMethod;
@end
- (void) privateMethod;
@end
Если вы поместите это в начало файла реализации, вы не получите предупреждения во время компиляции, когда отправите сообщение -privateMethod экземплярам AnObject. Имя в скобках (Private) — просто имя категории. Оно может быть любым. Обратите внимание на то, что без раздела @inmplementation, это просто станет ранним объявлением C функции. Если нет соответствующей реализации в C, вы получите ошибку линковщика. Если нет соответствующей реализации метода в Objective-C, вы получите исключение в рантайме.
Вы можете предоставить дополнительную реализацию метода, используя категорию точно таким же путем, как и когда вы предоставляли «нормальные» методы:
@implementation AnObject (NewMethods)
- (void) newMethod
{
...
}
@end
- (void) newMethod
{
...
}
@end
Если вы отправите сообщение -newMethod любому экземпляру AnObject, этот метод будет вызван. Вы также можете использовать это для замены существующих методов в объекте на свою собственную версию, поэтому вам не нужен доступ к объекту. Этот подход часто используется для дополнения различных методов библиотечных классов дополнительным функционалом, а также может быть использован для исправления багов в сторонних библиотеках, исходных кодов которых у вас нет.
Менее документированной частью категорий является то, что категории позволяют вам добавлять соответствия протоколов к существующим объектам. Если ваша категория перенимает протокол, вы получите предупреждение во время компиляции, если вы не предоставляете реализаций каждого метода, и станет возможным провести тесты во время исполнения программы для проверки соответствия. Мы использовали эту возможность в Étoilé для добавления соответствия коллекции протоколов ко всей коллекции классов в Foundation, дав им совместимый интерфейс.
Неформальные протоколы
Очень частым шаблоном в Objective-C является идея неформального протокола, — коллекции методов, которые класс может реализовывать, а может не реализовывать. Её частое использование — для делегирования объектов. В Java очень часто для делегатов ожидается реализация интерфейса. У такого подхода часто есть набор методов, некоторые из которых реализованы как методы без тела.
В Objective-C сть два пути для определения неформальных протоколов. Первый — определение категории на базовом классе (обычно на NSObject), которая предоставляет нулевые реализации каждого метода. Это означает, что каждый класс будет отвечать на сообщения в интерфейсе, но что-то действительно делать будут только реализованные методы. Вы должны поместить в файл исходного кода, который использует неформальный протокол, нечто следующее:
@implementation NSObject (MyInformalProtocol)
- (void) handleSomethingFrom:(id) sender {}
@end
- (void) handleSomethingFrom:(id) sender {}
@end
Затем вы просто отправляете сообщение handleSomethingFrom: делегированному объекту. Обратите внимание, что вам не нужен раздел @interface для создания разделения между интерфейсом и реализацией для категорий; интерфейс приватен, а вам не нужно, чтобы что-то ещё вызывало этот метод, кроме вашего класса, поэтому не открывайте интерфейс. Хотя этот метод прост, он не идеален во многих случаях, так как приводит к заполнению координирующей таблицы корневого объекта в основном не используемым хламом (который может привести к понижению производительности в рантайм Apple из-за того, как там реализовано кеширование).
Другой вариант — производить тестирование в рантайме. Если вы пошлете объекту сообщение respondsToSelector:, вы можете выяснить, реализует ли он названный метод. Для делегатов, вы можете затем кешировать IMP для метода, и вызвать его напрямую позже. В вашем методе setDelegate: будет нечто такое:
handleMethod = NULL;
if([delegate respondsToSelector:@selector(handleSomethingFrom:))
{
handleMethod = [delegate methodForSelector:\
@selector(handleSomethingFrom:)];
}
if([delegate respondsToSelector:@selector(handleSomethingFrom:))
{
handleMethod = [delegate methodForSelector:\
@selector(handleSomethingFrom:)];
}
Потом при использовании, вы делаете следующее:
// Эквивалентно [delegate handleSomethingFrom:self];
if (NULL != handleMethod
{
handleMethod(delegate, @selector(handleSomethingFrom:), self);
}
if (NULL != handleMethod
{
handleMethod(delegate, @selector(handleSomethingFrom:), self);
}
Objective-C 2.0 дает третий вариант, который предназначен для использования директивы @optional в объявлении протокола. Это большая трата памяти, так как вам необходимо производить тесты в рантайме для определения, реализует ли объект, сопоставленный протоколу, опциональный метод из этого протокола.
Повторная отправка
В C++ вы не посылаете сообщения, а вызываете функции-члены. Это важное отличие, так как оно обозначает, что вызываемые методы семантически схожи с вызовом функций. Objective-C вносит другой слой абстракции. Если вы посылаете сообщение объекту Objective-C, который его не понимает, возникнет исключение. Тем не менее, это не делается самим языком.
Библиотека рантайма имеет механизм устранения неисправностей, когда нет метода для селектора. Она вызывает метод, который интроспектирует получателя для некоторой информации о типе, помещает вызов в объект NSInvocation, а затем передает его методу -forwardInvocation: данного объекта.
Объект NSInvocation инкапсулирует получателя, селектор и аргументы. Вы можете использовать эту идею для отправки сообщений высокого порядка. Рассмотрим следующий пример:
[[anArray map] toUppercase];
Метод -map, примененный к массиву, возвращает объект прокси с помощью метода forwardInvocation:, реализованного подобным образом:
- (void) forwardInvocation:(NSInvocation*)anInvocation
{
SEL selector = [anInvocation selector];
NSMutableArray * mappedArray = [NSMutableArray array];
FOREACHI(array, object)
{
if([object respondsToSelector:selector])
{
[anInvocation invokeWithTarget:object];
id mapped;
[anInvocation getReturnValue:&mapped];
[mappedArray addObject:mapped];
}
}
[anInvocation setReturnValue:mappedArray];
}
{
SEL selector = [anInvocation selector];
NSMutableArray * mappedArray = [NSMutableArray array];
FOREACHI(array, object)
{
if([object respondsToSelector:selector])
{
[anInvocation invokeWithTarget:object];
id mapped;
[anInvocation getReturnValue:&mapped];
[mappedArray addObject:mapped];
}
}
[anInvocation setReturnValue:mappedArray];
}
FOREACHI — макрос из Étoilé, который просто производит кеширование IMP на NSEnumerator. Когда вы посылаете сообщение -toUppercase к мэп прокси, он производит итерацию по каждому объекту массива; проверяет, отвечает ли он селектору и, если да, вызывает метод с аргументами. Возвращаемое значение добавляется к новому массиву.
Это почти невозможно сделать в C++. Вы можете использовать шаблон команды, чтобы сделать нечто похожее, но только реализовав сначала ваш собственный механизм диспетчеризации.
Заключение
Objective-C очень небольшой язык и мы рассмотрели практически все в этой серии статей, включая некоторые продвинутые возможности. Тем не менее, как и в Smalltalk, он несколько вводит в заблуждение. В то время как ядро языка очень просто, большинство из окружения программ на Objective-C приходит из библиотеки. Обычно это реализация спецификации OpenStep, такие как GNUstep или Cocoa от Apple, а знакомство с библиотекой может занять много времени.
- Просмотров: 1557
Версия для печати
#1
Vanger |
Vanger |
Дата публикации: 22 февраля 2009 03:08 | ICQ: --
цитировать
цитировать
#2
MarrySun |
MarrySun | Скорее после первое намертво отпадает желание читать дальше) По мне так, если у тебя нету макбука или iPhone то нафиг сдался это obc....
Дата публикации: 22 февраля 2009 03:57 | ICQ: --
цитировать
цитировать
#3
Vanger |
Vanger | 
ммм
думаю тогда стоит самому сделать перевод, а не пользоваться готовым.
и написать более интересным языком))))
а так - канечн, objective c используется в ограниченном числе задач
зато в штатах доля эппла на рынке под 10%. В России около процента. а это миллионы юзеров. когото заинтересует
думаю тогда стоит самому сделать перевод, а не пользоваться готовым.
и написать более интересным языком))))
а так - канечн, objective c используется в ограниченном числе задач
зато в штатах доля эппла на рынке под 10%. В России около процента. а это миллионы юзеров. когото заинтересует
Дата публикации: 23 февраля 2009 15:05 | ICQ: --
цитировать
цитировать
#4
Джон Фрост |
Джон Фрост | ДА ну, меня не вштырило
Ничего клевого, просто каждый свое хвалит....
P.S. еле прочел три части....
P.S. еле прочел три части....
Дата публикации: 27 февраля 2009 16:55 | ICQ: --
цитировать
цитировать
#5
Vanger |
Vanger | 
мне сначала было интересно
основную идею посмотрел, быстро проглядел статьи
полностью все читать не стал, лично мне это не нужно, но кого-то заинтересует
сегодня на фри-ланс.ру видел объявление о поиске программеров для iphone софта
основную идею посмотрел, быстро проглядел статьи
полностью все читать не стал, лично мне это не нужно, но кого-то заинтересует
сегодня на фри-ланс.ру видел объявление о поиске программеров для iphone софта
Дата публикации: 28 февраля 2009 15:52 | ICQ: --
цитировать
цитировать


Просмотров: 3
Objective-C для программистов C++. Часть 2
Просмотров: 5
Objective-C для программистов C++. Часть 1
Просмотров: 14
--------------
первая часть самая интересная? ))))