Objective-c и c++, рождение

Objective-C и C++, рождение

Удивительно, но всего 15-20 лет назад между поклонниками этих языков шла чуть ли не война. Асимметричная. Со стороны “ущемляемого меньшинства”. “Большинство” даже не подозревало о существовании противника и не сопротивлялось.

Интересно: в наши дни кто-нибудь догадается какой из этих языков был “большинством”, а какой – наоборот? Открою еще одну Америку: у каждого из этих языков были и есть свои фирменные недостатки, и они оба относятся к великим языкам программирования.

Автору этих срок довелось “пожить” в этих языках, 6 лет в C++ и 15 в Objective-C, что ни о чем не говорит и ничего не гарантирует. Кроме того, пожалуй, что автор кое-что про эти языки знает…

Кто родился раньше?

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

Вот что мне удалось установить: информация об этих языках была впервые опубликована в 18 томе авторитетного издания SIGPLAN, в 1983 году. Про Objective-C – в первом номере этого тома, в январе. Про C++ – в каком-то другом (не первом) номере. То есть, позже. Ура!

А теперь разберемся. Эмоции, бушевавшие двадцать с лишним лет тому назад, больше не искажают реальность, и теперь я могу писать про Objective-C объективно. Архив SIGPLAN в сети есть, но доступ к текстам статей… платный.

Но это не единственный источник информации об этих языках. В 1979 году, датский программист Бьярн Строустроп пришел к выводу (который хоть и перестал в наши дни быть очевидным, но все еще правильный), что объектно-ориентированный подход на порядок ускоряет и облегчает разработку сложного программного обеспечения.

Вот только простому программисту в 1979 году этот подход был недоступен. А программы, которыми мы пользуемся, которые сразу любим и ненавидим, пишутся именно “простыми” программистами, которые занимаются этим непростым делом по 8-10 часов в день пять дней в неделю, год за годом…

Проект, разрабатываемый для себя, Бьярн назвал “C с классами” (C with Classes). Суть замысла была проста и логична: из всех преимуществ ООП (объектно-ориентированное программирование) важнее всего то, что ускоряет и облегчает разработку.

Поэтому “C с классами” был объектно-ориентированным языком только в исходном коде, где существовали классы и объекты, наследование и другие признаки ООП.

Компилятор превращал все эти теоретические построения в обычный процедурный код, который не уступал (в начале почти не уступал) по эффективности коду, написанному на традиционных языках программирования обычным способом, без привлечения магии.

С 1979 по 1983 Бьярн выполнил колоссальный объем работы, спроектировав и реализовав “улучшенный C”, добившись его устойчивой работы и даже опубликовал несколько статей о CwC (C with Classes), которые привлекли к ним внимание.

В 1983 году Бьярн решил, что язык имеет смысл не только для него, и что пришло время для его активного продвижения. Бьярн переименовал его в C++, написал статью в SIGPLAN и приступил к написанию книги “C++ Programming Language”.

C++ впервые был упомянут в 1983, в публикации в SIGPLAN – это правда, но не вся правда. К тому моменту это был реально существующий язык, его уже пробовали сотни (или даже тысячи) добровольцев. Перед публикацией его, всего лишь, переименовали в “дважды приплюснутый Си”.

В 1985 году C++ стал продаваться, и к началу 90-х тал главным языком программирования во всем мире. Я начал им пользоваться в 1995, по сравнению с Object Pascal C++ был как Боинг 787 по сравнению с кукурузником. Сложнее, разнообразнее, современнее. Мощнее, в конце концов.

Освоение C++ требовало времени и приличных усилий (язык непрост), но он того стоил.

Замысел, приведший к появлению Objective-C

Статья в первом номере 18 тома SIGPLAN называлась “The object-oriented pre-compiler: programming Smalltalk 80 methods in C language”. То есть, “Объектно-ориентированный пре-компилятор: программирование методов Smalltalk 80 на языке C”. В статье, и в отзывах на неё, для обозначения предка Objective-C использовали аббревиатуру OOPC.

В 1983 году OOPC появился в публичном пространстве, находясь в эмбриональной фазе своего развития. Он был чем-то вроде “C с классами”, но от еще одной команды.

Когда соотношение числа использующих Objective-C и C++ было примерно 1:1000, если не 1:10000 (умозрительная оценка), почему-то это причиняло боль и требовало оправданий. Оправдания были найдены: создатели Objective-C, Брэдли Кокс и Том Лав, названные в википедии “учеными”, будто бы просто экспериментировали, и вообще не планировали для него никакого коммерческого применения.

Просто так, ради чистой науки. Глава и владелец частной компании StepStone Брэд Кокс и один из сотрудников той же компании Том Лав. Ну да…

По сравнению с понятной и привлекательной для обычного программиста концепцией C++, замысел Брэда и Тома был глубже и, поскольку никто так и не смог его внятно и понятно изложить, казался заумным и притянутым за уши.

Но мы исправим их ошибку: замысел был что надо.

По старому программистскому поверью, в каждых ста строках нового кода, независимо от того насколько тщательно и педантично он тестируется, обязательно есть два серьезных бага, которые проявят себя только оказавшись в руках пользователей. При увеличении размера кода в N раз, число таких багов возрастает в N в третьей степени раз.

Это, естественно, преувеличение и шутка юмора, но реально существующая проблема в ней отражена точно. Есть ли способ решения этой проблемы? Есть.

Повторное использование кода (reuse). Код, который уже обкатан на пользователях, в котором уже выявили и истребили всех (почти всех) багов, заведомо надежнее чем новый, только что написанный, код.

В объектно-ориентированных средах программирования (типа Smalltalk) нужный эффект достигается проще и быстрее, чуть ли не сам собой (или при соблюдении определенной гигиены при принятии решений). Вот только… Этот подход, как уже сообщалось в эпизоде про создание C++, простому программисту в начале 80-х был практически недоступен.

Использовать Smalltalk можно было только на мощных рабочих станциях (то есть, на очень дорогих), даже на этих станциях написанный на Smalltalk код был невероятно медлителен. И лицензия на сам Smalltalk была, мягко говоря, не бесплатной.

А кроме того, язык был слишком необычен – как используемыми в нем принципами (всё, что в нем есть – объекты, включая числа и классы; все действия, в том числе арифметика, осуществляются отправкой сообщений от объекта к объекту…), так и синтаксисом.

Это не так сложно, как кажется. Язык был разработан в Xerox PARC (Palo Alto Research Center) в Learning Research Group (LRG, группе исследований процесса обучения), проект и группу возглавлял Алан Кэй, и разработчики Smalltalk проводили опыты над детьми.

Дети от 8 до 15 лет, после короткого и совсем несложного обучения основным принципам Smalltalk, запросто решали очень сложные задачи, приводя гостей центра в изумление. На решение подобных задач у взрослых и опытных программистов ушли бы месяцы…

Но взрослому, тем более профессионалу, тем более во власти привычек и под гнетом его производственной программы, совершить подобное насилие над собой намного сложней.

Рождение OOPC (Objective-C)

Брэд, Том и оставшиеся безымянными сотрудники StepStone, разработали OOPC, язык для пре-компилятора – код на “чистом C” с добавленными в него обращениями к объектно-ориентированной среде времени исполнения, полностью реализующей ОО-парадигму Smalltalk, за исключением двух её “фич”: сборщика мусора и замыканий.

ОО-парадигма Smalltalk звучит страшновато, на самом деле в С были добавлены три или четыре грамматические конструкции, и она директива. Минимум!

И сам пре-компилятор, который превращал исходные коды на OOPC в коды на обычном стандартном C – который скармливали стандартному компилятору, получая на выходе работающие программы.

Все это делалось в одним из Unix’ов, и к 1983 году работало безупречно. Среда времени исполнения, на порядок более “легкая”, чем аналогичная среда Smalltalk, устанавливалась в Unix’е легко, непринужденно и стандартными средствами.

Для тех, кто понимал что к чему, эффект был потрясающий.

Помимо “повторного использования кода”, о котором мечтали Брэд и Том, и которое эта система разве что делала более удобным и естественным (но его она не гарантировала), это была настоящая действующая объектно-ориентированная среда, аналоги которой стоили десятки (если не сотни) тысяч долларов, которой было достаточно самого обычного компьютера.

Замечательные инженеры и отличные программисты, они так и не смогли превратить созданное ими чудо в источник доходов, сделав его достоянием всего мира. Сколько они хотели за OOPC, неизвестно. Книгу (куда более необходимую для OOPC, чем для C++) они даже не пытались написать.

Канал распространения – через знакомых, знакомых этих знакомых, никакой рекламы. А Интернета еще не было. Трети желающих OOPC достался вообще за так.

В OOPC управление памятью (создание и уничтожение объектов) было делегировано C. Никаких счетчиков ссылок, они появились только в NeXTSTEP 2.0.

В базовом классе (благодаря особенностям OOPC, проблема “хрупкого базового класса” библиотекам OOPC не грозила) Object, был реализован механизм превращения любого объекта в “плоское” представление, для сохранения на диск, и для восстановления из “плоского” представления, и два метода, save и load, для переопределения в подклассах.

Библиотека OOPC была фрагментом библиотеки Smalltalk, в которой отсутствовало все, что связано с графическим пользовательским интерфейсом, с перехватом и обработкой событий, с графикой в любом виде – в современных терминах это был Foundation Kit.

В конце 80-х, когда NeXT взяла в аренду OOPC, язык и базовая библиотека OOPC почти не изменились. У StepStone, к тому времени, уже был полноценный компилятор Objective-C, но NeXT он чем-то не удовлетворил – и они разработали собственный, основанный на GCC.

Продолжение следует

Источник: https://AppleInsider.ru/istoriya-apple/objective-c-i-c-rozhdenie.html

Насколько отличается Objective-C от С++?

Краткий список некоторых основных отличий:

  • С++ допускает множественное наследование, Objective-C не работает.
  • В отличие от С++, Objective-C позволяет назначать параметры метода, а подпись метода включает только имена и типы параметров и тип возвращаемого значения (см. ниже комментарии bbum и Chuck). Для сравнения, сигнатура функции члена С++ содержит имя функции, а также только типы параметров /return (без их имен).
  • С++ использует bool, true и false, Objective-C использует bool, YES и NO.
  • С++ использует void* и nullptr, Objective-C предпочитает id и nil.
  • Objective-C использует «селекторы» (которые имеют тип SEL) в качестве приблизительного эквивалента указателям на функции.
  • Objective-C используется парадигма обмена сообщениями (a la Smalltalk), где вы можете отправлять «сообщения» объектам с помощью методов/селекторов.
  • Objective-C с радостью позволит вам отправить сообщение на nil, в отличие от С++, который выйдет из строя, если вы попытаетесь вызвать функцию-член nullptr
  • Objective-C позволяет динамическую отправку, позволяя определить класс, отвечающий за сообщение, во время выполнения, в отличие от С++, где объект, к которому вызывается метод, должен быть известен во время компиляции (см. комментарий wilhelmtell ниже). Это связано с предыдущей точкой.
  • Objective-C позволяет автогенерировать аксессуаров для переменных-членов, используя «свойства».
  • Objective-C позволяет назначать self и позволяет инициализаторам классов (аналогично конструкторам) возвращать совершенно другой класс, если это необходимо. Контраст с С++, где, если вы создаете новый экземпляр класса (либо неявно в стеке, либо явно через new), гарантированно будет того типа, который вы изначально указали.
  • Аналогично, в Objective-C другие классы также могут динамически изменять целевой класс во время выполнения, чтобы перехватывать вызовы методов.
  • Objective-C отсутствует функция пространства имен С++.
  • Objective-C отсутствует эквивалент ссылок на С++.
  • Objective-C не хватает шаблонов, предпочитающих (например), вместо этого разрешить слабую типизацию в контейнерах.
  • Objective-C не допускает перегрузку неявных методов, но С++ делает. То есть, в С++ int foo (void) и int foo (int) определяют неявную перегрузку метода foo, но для достижения того же в Objective-C требуются явные перегрузки — (int) foo и — (int) foo:(int) intParam. Это связано с тем, что параметры Objective-C, которые функционально эквивалентны кодовому имени С++.
  • Objective-C с радостью позволит методу и переменной использовать одно и то же имя, в отличие от С++, который обычно имеет подгонки. Я полагаю, что это связано с Objective-C с использованием селекторов вместо указателей на функции, и, следовательно, имена методов не имеют фактически «значения».
  • Objective-C не позволяет создавать объекты в стеке — все объекты должны быть выделены из кучи (либо явно с сообщением alloc, либо неявно в соответствующем методе factory).
  • Как и С++, Objective-C имеет как структуры, так и классы. Однако, если в С++ они рассматриваются как почти то же самое, в Objective-C они обрабатываются по-разному — вы можете создать структуры в стеке, например.
Читайте также:  Apple столкнулась с дефицитом некоторых версий iphone xr

На мой взгляд, вероятно, самая большая разница — это синтаксис. Вы можете добиться практически одинаковых вещей на любом языке, но, на мой взгляд, синтаксис С++ проще, тогда как некоторые из функций Objective-C упрощают задачу (например, графический интерфейс) благодаря динамической диспетчеризации.

Вероятно, много других вещей, которые я пропустил, я обновлю любые другие вещи, о которых я думаю. Кроме этого, вы можете очень рекомендовать гида, на который указал LiraNuna. Кстати, другой интересный сайт может быть this.

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

EDIT: обновлено для решения вопросов, поднятых в следующих комментариях, добавлено еще несколько элементов в список.

Источник: http://qaru.site/questions/44277/how-different-is-objective-c-from-c

Мини-гайд по началам изучения Objective C

Опять же, собрано для себя.

Введение

Язык Objective C, на первый взгляд, очень простой, чтобы начать программировать – достаточно базового знания Cи и слышать что-нибудь про SmallTalk, где вызов метода – это посылка сообщения.

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

Инструменты

Как это не странно, но каких-либо удобных инструментов под платформу Windows для этого языка не существует не найдено мной, к сожалению.

Поэтому как обычно, пришлось брать стандартный GCC (с поддержкой Objective C) и MakeFile в руки. Для редактирования текстов и исполнения программ, я уже который год подряд использую прекрасный, хоть уже слегка и устаревший редактор Scite.

Примечание: Официальную версию Scite можно взять тут. Однако, самой подходящей версией Scite, сейчас, видимо является – русская сборка, которая содержит ряд полезных дополнений к оригинальной версии и поддерживает скриптовый язык Lua.

И далее, компилировать GCC с поддержкой Objective-C:

Синтаксис

Ух, это просто сказка.

По сути, вы можете взять любую Си-программу и откомпилировать её компилятором Objective C. Полная обратная совместимость.

А всё дальнейшее – это расширения.

По сути, их несколько: новые ключевые слова, которые начинаются с символа ‘@’ (коммерческое At), посылка сообщения, обрамляемое квадратными скобками, и всё. Остальное делает рантайм – то есть библиотеки.

Например:

#import
#import @interface MyObject : Object
{ int field;
} -init;
-(void) Hello: (char*) s; @end @implementation MyObject -init
{ [super init]; field = 5;
} -(void) Hello: (char*) s
{ printf(«%s
«, s);
} @end int main(void)
{ MyObject* myObjectInstance = [[MyObject alloc] init]; [myObjectInstance Hello: «Hello, World!»]; [myObjectInstance free];
}Разбираем, по очереди.

#import – замена стандартного, и набившего всем C++-сникам оскомину, #include, – отличие с том, что #import включается ровно один раз при компиляции (да-да, та самая #pragma once).

objc/Object.h – базовый объект для всех объектов языка Objective-C. Он не является обязательным, но управление памятью реализовано в нём.

@interface – первое новое ключевое слово – это объявление нового объекта, содержит во-первых поля объекта (обычная C-структура) и объявления методов объекта в специфическом стиле.

@implementation – реализация объявленных в @interface методов объекта.

И самое интересное – это посылка сообщений.

MyObject * – указатель на объект.

[ObjectInstance Message: Parameter]

Итак, это обычные квадратные скобки, которые обозначают посылку сообщения Message некоторому объекту ObjectInstance. Сообщение может содержать упакованные параметры Parameter.

Суть примерно та же, что и в SmallTalk. Объекту можно посылать любые сообщения, обработаны будут только те, которые явно поддерживает объект.

В моём примере, происходит посылка четырёх сообщений:

  1) [MyObject alloc] – посылка сообщения классу MyObject о выделении памяти и создании объекта этого типа.

Примечание: Да, да, посылка сообщения происходит именно классу объектов. Классы объектов – являются самостоятельными объектами и все создаются во время старта приложения. Соответственно, возможно им посылать сообщения, и доступна интроспекция.

  2) Возвращаемому результату обработки сообщения (это указатель на созданный объект) посылается сообщение init, которое в языке Objective C является соглашением об инициализации объекта (конструктор в терминах других языков).

  3) [myObjectInstance Hello: «Hello, World!»] – посылка сообщения Hello c параметром.

  4) [myObjectInstance free] – освобождение памяти, ранее выделенной под объект через cообщение alloc.

Примечание: Строго говоря, вызов free – необязательно приводит к освобождению памяти, в связи с тем, что в Objective C для управления памятью используется подсчёт ссылок, а в некоторых случаях и GC.

Рантайм

Существует два немного различающихся рантайма: входящий в поставку GCC и от Apple. Отличия у них незначительные. Главное различие – это политика именования заголовочных файлов и классов объектов у Apple: везде добавляется префикс NS.

Примечание: NS – это сокращение от названия NextStep, историческое название предшественника сегодняшней MAC OS. Набор библиотек для Objective C под Windows доступен в пакете GNUStep.

Примеры:

GCC: #import Apple: #import

Аналогичный эппловскому набор рантайм-библиотек (в пределах небольших изменений) поставляется с библиотеками GNUStep.

Литература

Источник: http://andir-notes.blogspot.com/2011/09/objective-c.html

Стань X-кодером: Начинаем кодить под Mac OS с помощью Objective-C — «Хакер»

Содержание статьи

Несмотря на то, что для МакОСи можно создавать приложения на C/C++ или Java, Objective-C фактически стал стандартом при разработке под эту операционку. Это произошло благодаря удобному и функциональному API для этого языка — фреймворку Cocoa. Об ObjectiveC и Cocoa мы сегодня и поговорим.

Objective-C появился через год после плюсов, в 1986 году, благодаря работе Brad Cox и Tom Love в компании Stepstone. Они хотели соединить высокий уровень абстракции и повторного использования кода, характерные для объектно-ориентированного программирования, с производительностью и простотой синтаксиса языка С.

Для этого им пришлось модифицировать C, добавив некоторые фичи из Smalltalk, позволяющие работать с объектами. Получившееся объектно-ориентированное расширение языка С впоследствии стало носить название Objective-C — «объектный C».

Чтобы понять, как этот продукт скрещивания двух древних языков программирования попал на современные маки и разнообразные мобильные устройства Apple, нужно вспомнить историю яблочной компании… Apple была основана в 1980 Стивом Джобсом и Стивом Возняком.

После многих лет успеха на посту главы компании Джобса сменил бывший управляющий компании Coca-Cola Джон Скалли (John Sculley). Стив покинул Apple и через некоторое время основал новую компанию, назвав ее NeXT. Среди основных задач NeXT было создание операционной системы нового поколения.

Для ее разработки было решено использовать среди прочих средств и Оbjective-C — он стал основой для API. Вскоре операционка от NeXT была готова и получила название NeXTStep. Собственно, это и было первое серьезное применение ObjC.

Позже NeXT объединила усилия с Sun Microsystems для создания следующей версии NeXTStep — OPENStep (в настоящий момент продолжает свое существование только GNUStep, поддерживаемая сообществом свободного программного обеспечения).

В середине 1990-х Джон Скалли покинул Apple, которая стремительно теряла свои позиции на рынке. Для спасения ситуации компания решила создать новую операционную систему взамен устаревающей Mac OS. После нескольких неудачных попыток Apple решила купить компанию, которая уже имеет свою операционку.

Этой компанией, как ты уже наверно догадался, стала NeXT. Так Джобс снова оказался в Apple, на основе NeXTStep была создана Mac OS X, а Objective-C занял свое место среди инструментов Mac-разработчика и в API Mac OS X.

Итак, Objective-C — объектно-ориентированное расширение языка С. А что в нем, собственно, есть такого, чего нет в тех же плюсах? Среди основных достоинств Objective-C нужно перечислить следующие:

  • Синтаксис Objective-C очень прост. Чтобы его изучить, С-программисту понадобится всего пара дней. Он является именно расширением языка С, в него просто добавлены новые возможности для объектноориентированного программирования. Таким образом, абсолютно любая программа на С является программой и на Objective-C (что для С++, вообще-то, неверно).
  • Objective-C — message-oriented language, то есть объекты в нем общаются между собой не с помощью явного вызова инкапсулированных функций, как в C++ или Java, а при помощи отправки друг другу сообщений.

Это позволяет объекту-отправителю легко формировать нужное сообщение во время выполнения приложения, а объектуполучателю — принимать произвольные сообщения, обработка которых не была в нем реализована явно, так как поиск кода, выполняемого при получении объектом сообщения, осуществляется во время выполнения, а не на этапе компиляции программы. Так, если среда выполнения не находит в интерфейсе объекта сигнатуры входящего сообщения, ему все равно дается шанс обработать это сообщение с помощью специального метода. Подобная динамическая реализация вызова методов делает систему более гибкой, лишь незначительно понижая ее производительность.

Язык Objective-C предоставляет широкие возможности для работы с метаинформацией; так, у любого объекта непосредственно на этапе выполнения можно спросить его класс, список методов (с типами передаваемых аргументов) и instance-переменных, проверить, является ли класс потомком заданного и поддерживает ли он заданный протокол (протокол — это список сообщений, на которые отвечает данный объект, некоторое подобие абстрактных классов C++ или интерфейсов Java) и т.д.

Линус Торвальдс как-то сказал: «Разговоры — дешевка. Покажите мне код!». Показываю! Вот код HelloWorld , а на Obj-C. Кстати, если у тебя нет под рукой Mac OS X или хакинтоша, можешь попробовать в действии Objective-C и Cocoa c помощью GCC и проекта OpenStep.

Наша первая прога на ObjC

#import void main() { NSLog(@»Hello world!»);

}

Наш HelloWorld сильно напоминает C++, не так ли? Но есть и свои особенности, которые ты, конечно, сразу заметил.

  • #import — директива препроцессора, аналогичная #include, но, в отличие от последней, она не позволяет включить заголовок более одного раза, то есть работает так же, как стражи включения в C++ (#include, разумеется, тоже поддерживается).
  • Cocoa.h — заголовок, содержащий описания функций, классов и констант фреймворка Cocoa, о котором я говорил в начале.
  • NSLog — одна из таких функций. Она выводит текстовое сообщение в stdout вместе с timestamp’ом в начале строки. Помнишь NeXTStep? Префикс «NS» как раз оттуда :).

Строки в Objective-C — отдельная история. NSLog получает на вход не C-строку, а объект класса NSString.

Заметил собаку перед строкой в NSLog? Это указание компилятору ObjC создать константу типа NSString — в Сocoa используются не zerro-terminated строки, как в C, а объекты класса NSString или его наследников (NSMutableString например).

Читайте также:  Apple нарастила оперативку некоторых модификаций ipad pro 2018 до 6 гб

Создатели Cocoa позаботились о том, чтобы в NSString были реализованы все методы работы со строками, которые тебе чаще всего приходится использовать. Строки можно склеивать, разбивать по разделителю, искать в них подстроки, делать форматированный вывод и много чего другого.

https://www.youtube.com/watch?v=UgQytaPxUUY

На скриншоте ты можешь видеть код нашего простенького примера в среде XCode и результат его выполнения. XCode — это среда разработки, используемая при написании приложений для Mac OS и iOS. В ней довольно удобно работать, но, как и ко всему новому, к ней нужно привыкнуть.

Кроме редактора и отладчика в нее интегрированы средства построения пользовательского интерфейса — «Interface Builder», управления версиями — «SCM» и еще множество всяких полезных фишек. В качестве компилятора используется допиленный Apple GCC. В качестве отладчика — GDB.

В настоящий момент на сайте Apple свободно доступна для скачивания XCode 3, пробная версия XCode 4 доступна только для зарегистрированных Appleразработчиков. В общем, качай, устанавливай, пробуй…

Раз язык объектно-ориентированный, значит, в нем должны быть объекты. Давай посмотрим, как их создавать и использовать в Objective-C. Каждый класс в коде на Objective-C разделен на интерфейс и реализацию, которые принято хранить в отдельных файлах. Заголовочные файлы получают расширение «h», а файлы с реализацией — «m».

В интерфейсе класса описывается его имя, класс-предок, если такой есть, реализуемые протоколы, список публичных, приватных и защищенных полей, сообщения, на которые отвечает класс и объекты этого класса.

// Класс Dog — наследник NSObject // Разместим его интерфейс в «Dog.h» @interface Dog : NSObject { // Здесь размещаем поля объекта @private int Age; @public int Color; } // После этого идет описание сообщений, // на которые отвечает объект.

// Перед сообщениями экземпляров ставится «-», // а перед сообщениями класса // (аналог статических методов в C++) — знак «+». // В описании сообщения указывается имя // сообщения, список передаваемых параметров // и тип возвращаемого значения.

— (void) voice; — (void) setAge: (int) age; — (int) getAge; @end // Реализация сообщений нашего класса (Dog.

m) @implementation Dog — (void) voice { NSLog(@»Woof woof»); } // Вообще, для этого есть свойства, // но о них как-нибудь в следующий раз — (void) setAge: (int) age { Age = age; } — (int) getAge { return Age; }

@end

Для вызова метода используется следующий синтаксис:

[my_class_pointer message_name: arg1 arg2_name: arg2 arg3_name: arg3]

Например:

[dog1 setAge: 3];

Немного непривычно после точек и стрелок C++ и Java, но к такому синтаксису быстро привыкаешь и даже начинаешь считать его удобным. Что интересно, мы можем посылать сообщения нулевому указателю (nil). Результат всегда будет nil.

После того, как класс описан и определена реализация для методов-обработчиков сообщений, можно создавать объекты этого класса. Для того, чтобы создать объект, нужно сделать две вещи — выделить для него память и инициализировать ее. В Objective-C эти два действия разделены. Это может показаться излишним, но на самом деле придает процессу создания объектов дополнительную гибкость.

Чтобы создать объект Dog, нам потребуется следующая строчка:

Dog * dog1 = [[Dog alloc] init];

alloc — метод класса NSObject. Он выделит необходимое количество памяти под наш объект и вернет указатель на него. После этого мы можем выполнить инициализацию, послав только что созданному объекту сообщение init.

Мы не переопределяли обработку сообщений alloc и init, поэтому будут использованы реализации из NSObject. На практике init часто приходится переопределять для того, чтобы произвести какую-то начальную настройку объекта или передать дополнительные параметры.

init играет роль конструктора в ObjC.

Теперь, когда мы создали экземпляр класса, мы имеем полное право отправлять ему сообщения:

int age = [dog1 getAge];
[dog1 voce];

Для того, чтобы уничтожить объект и освободить выделенную ему память и (возможно) другие ресурсы, ему нужно отправить сообщение release:

[dog release];

Управление памятью реализовано в ObjC в виде подсчета ссылок. alloc создает объект с числом ссылок, равным единице. release уменьшает количество ссылок для данного объекта на 1. Объект будет уничтожен, когда счетчик достигнет 0. Если тебе когданибудь приходилось использовать COM, то такая реализация управления памятью должна быть тебе хорошо знакома.

Значение счетчика можно увеличивать, посылая объекту сообщение retain. Кстати, начиная с Objective-C 2.0, стала доступна сборка мусора, ее можно совмещать с классическим управлением памятью с помощью подсчета ссылок.

Кроме явного уничтожения объекта, ты можешь добавить его в пул временных объектов (NSAutoreleasePool), послав сообщение autorelease.

Так часто поступают, например, при возвращении объектов методы классов Cocoa (метод stringByAppendingString объектов NSString, например).

NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; NSString *str; // Проинициализируем строчку и добавим // ее в pool str = [[[NSString alloc] init] autorelease]; // …

[pool drain]; // Здесь объект str будет уничтожен

В этом кратком обзоре ObjC следует, пожалуй, сказать еще об исключениях Objective-C. Обработка ошибок времени выполнения в С трудоемка и может порождать множество других ошибок.

На самом деле в C есть два варианта обработки ошибок времени выполнения — возвращение значения функцией и изменение значения глобальной переменной (errno например).

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

Код нормального процесса исполнения и код обработки ошибок смешивается, что не есть хорошо. К счастью, в ObjC, как и в C++, есть механизм исключений.

Вот пример обработки исключительной ситуации в ObjC:

Обработка исключений в Objective-C

Cup * cup = [[Cup alloc] init]; @try { [cup fill]; } @catch ( NSException * exc ) { NSLog ( @»Exception caught: %@», exc ); } @finally { [cup release];

}

Конечно, описать полностью стандарт языка в одной короткой статье невозможно. Поэтому, если ты заинтересовался, я привел ссылки на некоторые полезные ресурсы.

После экскурса по Objective-C можно поговорить о доступных фреймворках МакОСи. Куда же без них? Фреймворк сделает за тебя всю грязную работу, чтобы ты мог спокойно заниматься основной задачей.

Для разработки нативных приложений под МакОСь распространение получили два фреймворка — Cocoa и Carbon. Если ты пишешь под Мак или под iOS на Objective-C, то твой выбор — Cocoa.

Cocoa — это продукт эволюции программных сред NeXTSTEP и OPENSTEP, которые разрабатывались компанией NeXT. Перекочевав на Mac OS X, фреймворк сильно изменился, и в нем появилось множество новых классов. Все они, как в С# или Java, являются наследниками одного класса — NSObject.

В Cocoa представлены базовые типы, такие как NSNumber и NSString, различные контейнеры (NSArray, NSDictionary), обертки для системных объектов и т.д. Давай-ка опробуем Cocoa и Objective-C в действии и создадим небольшое консольное Cocoa-приложение.
В Сети существует множество веб-сервисов. Некоторые из них просто предоставляют информацию в удобном формате, например, в XML.

Одним из таких сервисов является сервис Российского Центробанка, предоставляющий информацию о текущих курсах валют. По адресу www.cbr.ru/scripts/XML_daily.asp можно получить XML’ку следующего вида:

036 AUD 1 29,4185 … 944 AZN 1 38,6777<\p>

Создадим класс ObjC RCBDayly, который будет скачивать эту XML’ку, парсить ее и предоставлять данные в удобном для нас виде. Исходник нашего класса ты можешь увидеть на врезке.

На этом примере ты можешь видеть, как легко в Cocoa работать с сетью и XML. При создании подобных приложений можно обойтись, конечно, и средствами POSIX, а вот если ты хочешь создать GUI-приложение, без Cocoa тебе не обойтись. Но об этом как-нибудь в другой раз.

Разнообразные гаджеты от Apple производятся и продаются по всему миру в огромном количестве. Всех их объединяет то, что на них работает Mac OS X или iOS и, если ты хочешь освоить разработку под эти операционки, знания Objective-C тебе очень пригодятся. До встречи в эфире!

// Импортируем классы Cocoa #import // Опишем интерфейс нашего класса @interface RCBDayly : NSObject { @private // NSMutableDictionary — аналог map в C++ NSMutableDictionary * Valutes; } // Конструктор принимает на вход URL веб-сервиса

-(RCBDayly ) initWithContentsOfURL:(NSURL)url;

// Для доступа к данным класса будем использовать // метод getValueForCharCode.

-(NSString ) getValueForCharCode: (NSString *) char_code; @end // А теперь — реализация @implementation RCBDayly

-(RCBDayly

) initWithContentsOfURL:(NSURL) url { // Проинициализируем базовый класс — NSObject [super init]; // Подгружаем xml,ку с указанного URL NSError * err = nil; NSXMLDocument * cbr_xml = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err]; if (err != nil && [err code] != 0) { // Не повезло. Возможно, сервис недоступен, или // XML-парсер не смог разобрать документ. // Выяснить, что именно произошло, нам поможет // locolizedDescription из NSError NSLog(@»Error:%@», [err localizedDescription]); // Освободим память, выделенную под наш объект [self release]; return nil; } // Создадим NSMutableDictionary Valutes = [[NSMutableDictionary alloc] init]; // Нам потребуется массив XML-элементов NSArray * nodes = nil; // Заполним его элементами «Valute» из XML’ки nodes = [[cbr_xml rootElement] elementsForName: @»Valute»]; // Для каждой валюты получим ее CharCode и // Value (курс) for (int i = 0; i < [nodes count]; ++i) { NSXMLElement * valute = (NSXMLElement *)[nodes objectAtIndex: i]; NSArray * names = nil; names = [valute elementsForName: @"CharCode"]; NSArray * values = nil; values = [valute elementsForName: @"Value"]; // У валюты есть и имя, и курс? if ([names count] > 0 && [values count] > 0) { // Добавим пару CharCode — Value в наш // NSMutableDictionary [Valutes setObject: [(NSXMLElement *) [values objectAtIndex: 0] stringValue] forKey:[(NSXMLElement *) [names objectAtIndex: 0] stringValue]]; } // Вернем указатель на себя, как любой нормальный // конструктор return self; } // В этом методе мы просто обеспечиваем // доступ к private-полю Valutes

-(NSString

) getValueForCharCode:

(NSString*) char_code { return [Valutes objectForKey: char_code]; } @end int main(int argc, char *argv[]) { // Создадим пул для временных объектов, // которые генерит, например, [NSURL URLWithString] NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Создадим объект класса RCPDayly и // инициализируем его нужным URL RCBDayly * dayly_values = [[RCBDayly alloc] initWithContentsOfURL: [NSURL URLWithString: @»http://www.cbr.ru/scripts/XML_daily.asp»]]; if (dayly_values == nil) { // Произошла ошибка при инициализации класса return -1; } // Почем сегодня доллар? 🙂 NSLog([dayly_values getValueForCharCode:@»USD»]); [pool release]; // Освободим пул, а вместе с ним // и все временные объекты. return 0;

}

Cocoa — набор классов и функций Objective-С, предоставляющих доступ к сервисам Mac OS X для пользовательских приложений.

Поскольку для взаимодействия с классами Cocoa необходима среда выполнения ObjC, разработка с использованием этого фреймворка возможна только на Objective-C.

Для Сocoa существует возможность кроссплатформенной разработки под Linux и Windows благодаря проектам GNUStep и cocotron.

Carbon — процедурный фреймворк Mac OS X, предназначенный для использования в приложениях на C/C++. Он предоставляет обратную совместимость с более ранними версиями Mac OS (например, Mac OS 9).

В настоящее время возможности Carbon для работы с Mac OS X становятся все скромнее. Так, например, невозможно получить доступ к GUI из приложения Carbon для 64-битного окружения — Apple отдает предпочтение Cocoa.

Источник: https://xakep.ru/2011/05/10/55233/

Objective-C Runtime. Теория и практическое применение

В данном посте я хочу обратиться к теме, о которой многие начинающие iPhone-разработчики часто имеют смутное представление: Objective-C Runtime.

Многие знают, что он существует, но каковы его возможности и как его использовать на практике?
Попробуем разобраться в базовых функциях этой библиотеки.

Материал основан на лекциях, которые мы в Coalla используем для обучения сотрудников.

Что такое Runtime?

Objective-C задумывался как надстройка над языком C, добавляющая к нему поддержку объектно-ориентированной парадигмы.

Читайте также:  Next apple

Фактически, с точки зрения синтаксиса, Objective-C — это достаточно небольшой набор ключевых слов и управляющих конструкций над обычным C.

Именно Runtime, библиотека времени выполнения, предоставляет тот набор функций, которые вдыхают в язык жизнь, реализуя его динамические возможности и обеспечивая функционирование ООП.

Базовые структуры данных

Функции и структуры Runtime-библиотеки определены в нескольких заголовочных файлах: objc.h, runtime.h и message.h. Сначала обратимся к файлу objc.h и посмотрим, что представляет из себя объект с точки зрения Runtime:

typedef struct objc_class *Class;
typedef struct objc_object { Class isa;
} *id;

Мы видим, что объект в процессе работы программы представлен обычной C-структурой. Каждый Objective-C объект имеет ссылку на свой класс — так называемый isa-указатель. Думаю, все видели его при просмотре структуры объектов во время отладки приложений. В свою очередь, класс также представляет из себя аналогичную структуру:

struct objc_class { Class isa;
};

Класс в Objective-C — это полноценный объект и у него тоже присутствует isa-указатель на «класс класса», так называемый метакласс в терминах Objective-C. Аналогично, С-структуры определены и для других сущностей языка:

typedef struct objc_selector *SEL;
typedef struct objc_method *Method;
typedef struct objc_ivar *Ivar;
typedef struct objc_category *Category;
typedef struct objc_property *objc_property_t;

Функции Runtime-библиотеки

Помимо определения основных структур языка, библиотека включает в себя набор функций, работающих с этими структурами. Их можно условно разделить на несколько групп (назначение функций, как правило, очевидно из их названия):

  • Манипулирование классами: class_addMethod, class_addIvar, class_replaceMethod
  • Создание новых классов: class_allocateClassPair, class_registerClassPair
  • Интроспекция: class_getName, class_getSuperclass, class_getInstanceVariable, class_getProperty, class_copyMethodList, class_copyIvarList, class_copyPropertyList
  • Манипулирование объектами: objc_msgSend, objc_getClass, object_copy
  • Работа с ассоциативными ссылками

Пример 1. Интроспекция объекта

Рассмотрим пример использования Runtime библиотеки. В одном из наших проектов модель данных представляет собой plain old Objective-C объекты с некоторым набором свойств:

@interface COConcreteObject : COBaseObject @property(nonatomic, strong) NSString *name;
@property(nonatomic, strong) NSString *title;
@property(nonatomic, strong) NSNumber *quantity; @end

Для удобства отладки хотелось бы, чтобы при выводе в лог печаталась информация о состоянии свойств объекта, а не нечто вроде . Поскольку модель данных достаточно разветвленная, с большим количеством различных подклассов, нежелательно писать для каждого класса отдельный метод description, в котором вручную собирать значения его свойств. На помощь приходит Objective-C Runtime:

@implementation COBaseObject — (NSString *)description { NSMutableDictionary *propertyValues = [NSMutableDictionary dictionary]; unsigned int propertyCount; objc_property_t *properties = class_copyPropertyList([self class], &propertyCount); for (unsigned int i = 0; i < propertyCount; i++) { char const *propertyName = property_getName(properties[i]); const char *attr = property_getAttributes(properties[i]); if (attr[1] == '@') { NSString *selector = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; SEL sel = sel_registerName([selector UTF8String]); NSObject * propertyValue = objc_msgSend(self, sel); propertyValues[selector] = propertyValue.description; } } free(properties); return [NSString stringWithFormat:@"%@: %@", self.class, propertyValues]; } @end

Метод, определенный в общем суперклассе объектов модели, получает список всех свойств объекта с помощью функции class_copyPropertyList.

Затем значения свойств собираются в NSDictionary, который и используется при построении строкового представления объекта. Данный алгоритм раработает только со свойствами, которые являются Objective-C объектами.

Проверка типа осуществляется с использованием функции property_getAttributes. Результат работы метода выглядит примерно так:

2013-05-04 15:54:01.992 Test[40675:11303] COConcreteObject: { name = Foo; quantity = 10; title = bar;

}

Сообщения

Система вызова методов в Objective-C реализована через посылку сообщений объекту. Каждый вызов метода транслируется в соответствующий вызов функции objc_msgSend:

// Вызов метода
[array insertObject:foo atIndex:1];
// Соответствующий ему вызов Runtime-функции
objc_msgSend(array, @selector(insertObject:atIndex:), foo, 1);

Вызов objc_msgSent инициирует процесс поиска реализации метода, соответствующего селектору, переданному в функцию. Реализация метода ищется в так называемой таблице диспетчеризации класса.

Поскольку этот процесс может быть достаточно продолжительным, с каждым классом ассоциирован кеш методов. После первого вызова любого метода, результат поиска его реализации будет закеширован в классе.

Если реализация метода не найдена в самом классе, дальше поиск продолжается вверх по иерархии наследования — в суперклассах данного класса.

Если же и при поиске по иерархии результат не достигнут, в дело вступает механизм динамического поиска — вызывается один из специальных методов: resolveInstanceMethod или resolveClassMethod. Переопределение этих методов — одна из последних возможностей повлиять на Runtime:

+ (BOOL)resolveInstanceMethod:(SEL)aSelector { if (aSelector == @selector(myDynamicMethod)) { class_addMethod(self, aSelector, (IMP)myDynamicIMP, «v@:»); return YES; } return [super resolveInstanceMethod:aSelector];
}

Здесь вы можете динамически указать свою реализацию вызываемого метода. Если же этот механизм по каким-то причнам вас не устраивает — вы можете использовать форвардинг сообщений.

Пример 2. Method Swizzling

Одна из особенностей категорий в Objective-C — метод, определенный в категории, полностью перекрывает метод базового класса. Иногда нам требуется не переопределить, а расширить функционал имеющегося метода.

Пусть, например, по каким-то причинам нам хочется залогировать все добавления элементов в массив NSMutableArray. Стандартными средствами языка этого сделать не получится.

Но мы можем использовать прием под названием method swizzling:

@implementation NSMutableArray (CO) + (void)load { Method addObject = class_getInstanceMethod(self, @selector(addObject:)); Method logAddObject = class_getInstanceMethod(self, @selector(logAddObject:)); method_exchangeImplementations(addObject, logAddObject);
} — (void)logAddObject:(id)aObject { [self logAddObject:aObject]; NSLog(@»Добавлен объект %@ в массив %@», aObject, self);
} @end

Мы перегружаем метод load — это специальный callback, который, если он определен в классе, будет вызван во время инициализации этого класса — до вызова любого из других его методов.

Здесь мы меняем местами реализацию базового метода addObject: и нашего метода logAddObject:.

Обратите внимание на «рекурсивный» вызов в logAddObject: — это и есть обращение к перегруженной реализации основного метода.

Пример 3. Ассоциативные ссылки

Еще одним известным ограничением категорий является невозможность создания в них новых переменных экземпляра. Пусть, например, вам требуется добавить новое свойство к библиотечному классу UITableView — ссылку на «заглушку», которая будет показываться, когда таблица пуста:

@interface UITableView (Additions) @property(nonatomic, strong) UIView *placeholderView; @end

«Из коробки» этот код работать не будет, вы получите исключение во время выполнения программы. Эту проблему можно обойти, используя функционал ассоциативных ссылок:

static char key; @implementation UITableView (Additions) -(void)setPlaceholderView:(UIView *)placeholderView { objc_setAssociatedObject(self, &key, placeholderView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} -(UIView *) placeholderView { return objc_getAssociatedObject(self, &key);
} @end

Любой объект вы можете использовать как ассоциативный массив, связывая с ним другие объекты с помощью функции objc_setAssociatedObject. Для ее работы требуется ключ, по которому вы потом сможете извлечь нужный вам объект назад, используя вызов objc_getAssociatedObject.

Заключение

Теперь вы располагаете базовым представлением о том, что такое Objective-C Runtime и чем он может быть полезен разработчику на практике. Для желающих узнать возможности библиотеки глубже, могу посоветовать следующие дополнительные ресурсы:

Источник: http://www.pvsm.ru/objective-c/33719

Введение в Objective-C для знатоков C++

Различия между C++ и Objective-C не столь уж и велики, тем более что теперь референсную реализацию Objective-C предоставляет компилятор clang, в котором парсер и библиотека семантических проверок обрабатывают оба языка разом.

Ну а раз такое дело, то я постараюсь написать введение в Objetive-C в пределах одного поста. Вам потребуется окружение для разработки на Objective-C: система Mac OS X и XCode. Возникающие по ходу дела вопросы легко гуглятся в английском переводе на stackoverflow либо в документации от Apple.

Считается, что в ObjC код не «вызывает метод объекта», а «отправляет сообщение». Семантически разница только в добавлении утиной типизации («ducky typing») и «nil object», об этом — ниже.

Но есть и синтаксическое различие — вместо круглых скобок в конце имени метода ставятся квадратные скобки вокруг объекта и сообщения, а точка заменяется пробелом

#import
#include
#include void foo1()
{ std::string cxxString = «text»; const int cxxLength = cxxString.length(); NSString *nsString = @»text»; // @»» — литерал, создающий (NSString *) const int nsLength = [nsString length];
}
Кстати, в Objective-C принято работать с указателями на объекты. В C++, напротив, этого избегают по возможности с помощью RAII. В сообщениях с несколькими аргументами имя разбивается на несколько кусков. Вот как используется сообщение setObject:forKey:#import
#include
#include void foo3()
{ NSMutableDictionary *dict = [[NSMutableDictionary new] autorelease]; [dict setObject:@»string object» forKey:@»it's key»];
}Примечание: Есть более хитрые и одновременно редкие конструкции: перечисление нескольких аргументов в одном куске сообщения через запятую или пустая часть имени сообщения, состоящая из одного лишь двоеточия.

Ключевое слово @interface используется там, где в других языках — class. Слово @protocol пишут там, где в других языках interface (в C++ — класс с чисто виртуальными методами).

Есть возможность дополнить чужой класс своими методами с помощью категорий («categories»).

Кроме того, каждому @interface соответствует один @implementation, и в отличие от C++ можно перегружать методы базовых классов и добавлять новые прямо внутри @implementation, без декларирования в @interface.

Это необычное имя пошло от фразы, в переводе звучащей так:

Воспринимать название надо буквально =). Если у объекта есть методы сообщения objectiAtIndex: и count, то этот объект сойдёт за NSArray. Вы можете явно привести тип такого объекта к NSArray, и работать с ним как с NSArray.

Примечание: если вам придётся переписывать такой «утиный» код на C++, воспользуйтесь рефакторингом extract interface (скорее всего, придётся сделать его вручную).

То есть определите набор используемых методов и создайте интерфейс, а свои классы унаследуйте от него; передавайте указатель/ссылку на интерфейс вместо указателя на MyArray.

В крайнем случае такое не прокатит и придётся дублировать метод для MyArray и MyPseudoArray (или использовать шаблоны, в которых тоже действует утиная типизация).

Объект nil принимает любое сообщение и возвращает nil (который автоматически преобразуется в 0 или false при необходимости).

Примечание: Для долговечных систем это не самый удачный подход — если вы по ошибке инициализируете NSArray* нулём и начнёте с ним работать, программа не упадёт, но и работать правильно не будет.

К тому же, разыменование нулевого указателя фатально лишь для одного потока, а программа ещё может воскреснуть (как это делают LLVM и clang). Но для быстрой разработки это позволяет писать меньше кода.

Проблемы тут нет, сама Apple использует C и C++ для написания сложной логики.

Как вы уже догадались, в Objective-C строки и другие сущности являются объектами. Также они наследуются от NSObject и могут принимать соответствующие сообщения, такие как isKindOfClass:.

Семантически работа с объектами ObjC не отличается от работы с std::shared_ptr. Технически, разница есть: счётчик ссылок хранится внутри объекта, а его увеличение или уменьшение можно выполнять явно сообщением retain или release. Для лучшего понимания я покажу, как сделать похожий счётчик ссылок на C++:

class RefCountedBase
{
public: void retain() { ++m_refCount; } void release() { —m_refCount; if (0 == m_refCount) { delete this; } } protected: RefCountedBase() : m_refCount(1) { } private: int m_refCount; RefCountedBase(const RefCountedBase &) = delete; RefCountedBase &operator=(const RefCountedBase&) = delete;
};В ObjC это немного сложнее, чем в примере:

  • Сообщения retain/release возвращают id (≈NSObject*), так что благодаря ducky typing их можно писать внутри выражений.
  • Есть сообщение autorelease, которое вызывает отложенное уменьшение счётчика — ваш объект будет жить, пока не вы не вернёте управление  системному коду, вызвавшему ваш код. Например, в основном потоке крутится цикл обработки сообщений (что типично для GUI приложений), и объект не будет удалён до возвращения к этому циклу.
  • Есть сообщение copy, копирующее объект. При этом счётчик ссылок будет равен единице.

С недавних пор появился режим автоматического подсчёта ссылок, который может потребовать изменений в коде. Во всяком случае, retain/release/autorelease вызывать в этом режиме уже нельзя.

В ObjC есть цикл for-in, дествующий аналогично range-based for из C++ 2011:

#import
#include
#include void foo2()
{ std::vector cxxArray = {«a», «b», «c»}; for (auto s : cxxArray) std::cout

Источник: http://sergey-shambir.blogspot.com/2013/04/objective-c-c.html

Ссылка на основную публикацию