Objective-C

Всё программирование для iPhone и Cocoa MacOS X ведётся с помощью языка Objective-C.
Objective-C создан в давних 80-ых Брэдом Коксом и Томом Лав. Objective-C является надстройкой надо языком С и даёт возможность писать обычный С-код. Objective-C привносит объектно-ориентированные возможности, которые заимствует у Smalltalk. Первоначально концепции и терминология Objective-C вызывает некоторое замешательство. Но тут дело привычки и после недолгой работы, странный синтаксис уже не выглядит так непривычно.

Итак, Objective-C — это объектно-ориентированный язык, что значит полную поддержку объектов, членов-данных, методов, инкапсуляции, наследования и полиморфизма и всего что с этим связано. Заголовочный файл (.h) и файл реализации (.m) — вместе представляют собой объект в терминах Objective-C. В какой-то момент времени вы будете использовать встроенные объекты, которые поставляются с framework iPhone OS, но гораздо чаще вам придётся разрабатывать новые классы или наследоваться от уже существующих, чтобы добавить новое поведение. Когда будете это делать, вам необходимо будет добавить новую пару файлов (.h) и (.m), которые будут представлять ваш новый класс.

Рассмотрим шесть основных синтаксических элементов языка Objective-C:

  • Category — категория применяется для того, чтобы расширить класс без использования механизма наследования;
  • Class — класс он и есть класс, определяет тип объекта;
  • Message — сообщение, это команда, которая посылается объекту. Другими словами — вызов метода;
  • Properties — свойства дают возможность удобного использования методов Get/Set;
  • Protocols — протокол определяет методы, которые обязательны для реализации, по аналогии с interface в C#;
  • @ — директива, используется компилятором.

Теперь по порядку.

Message — сообщение

Сообщение посылается, когда один объект просит дугой выполнить определённое действие. Говоря привычным нам языком — послать сообщение, значит выполнить вызов функции/метода. Вызов простого сообщения выглядит следующим образом:

[receiver message];

Более жизненные пример:

[window makeKeyAndVisible];

Здесь сообщение посылает объекту window команду makeKeyAndVisible, которая говорит ему отобразиться и начать принимать ввод от пользователя.

Если бы я делал то же самое на C#, то приведённая конструкция была бы записана window.makeKeyAndVisible(); На первых порах это мне это было воспринимать легче, позже привык к записи Objective-C.

Есть еще три способа использования сообщения:

  1. сообщение может принимать аргументы;
  2. сообщения можно каскадировать;
  3. сообщение может быть передано одному из нескольких получателей.

Сообщение с аргументами

Чтобы отправить сообщение с одним аргументом, достаточно разделить двоеточием именем сообщения и аргументом. Пример:

[receiver message:argument];

Пример из жизни:

[textView setText:@"Hello World!"];

В C# я бы написал вот так: textView.setText(@«Hello world!»);

Если необходимо отправить сообщение с несколькими аргументами, тогда каждый аргумент, кроме первого снабжается меткой. Пример:

[receiver message:arg1 label2:arg2 label3:arg3];

Пример из жизни:

[myButton setTitle:@"OK" forState:UIControlStateNormal];

В C# я бы написал вот так myButton.setTitle(@«OK», UIControlStateNormal);

Чего бы я не смог повторить в C# так это использование меток. Метки дают возможность использовать аргумент не думая об его последовательности в списке аргументов, достаточно знать метку аргумента.

Каскадные сообщения

Тут думаю всё понятно. Сообщения мы можем каскадировать вкладывая одно в другое, пример:

[[UITextView alloc] initWithFrame:textFieldFrame];

Другими словами это выражение можно было бы записать:

UITextView *tmp = [UITextView alloc];
[tmp initWithFrame:textFieldFrame];

Получатели сообщения

Сообщение можно отправить классу:

[class message];

Пример:

UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];

В примере классу UIButton отправляется сообщение buttonWithType с аргументом UIButtonTypeRoundedRect. То же самое в C# я бы написал так: UIButton myButton = UIButton.buttonWithType(UIButtonTypeRoundedRect);

Получается, что метод buttonWithType класса UIButton является статическим.

Сообщение можно отправить объекту (экземпляру) класса, пример я уже приводил выше

UITextView *tmp = [UITextView alloc];
[tmp initWithFrame:textFieldFrame];

здесь сообщение initWithFrame с аргументом textFieldFrame отправляется объекту (экземпляру) класса UITextView.

Есть еще два ключевых слова, используя которые мы можем отправить сообщение объекту класса:

[self setText:@"Hello World!"];

Думаю тут всё понятно. В C# я бы написал вот так: this.setText(@«Hello World!»);

[super initWithFrame:frame];

Отправляем сообщение предку. В C# я бы записал это так: base.initWithFrame(frame);

Определение класса

Интерфейс

Классы в Objective-C определяются в паре файлов (.h), (.m). В файле (.h) определяется интерфейс класса, а в файле (.m) реализация этого класса. Определение интрерфейса класса начинается с директивы @interface и заканчивается директивой @end. Сразу же пример:

///
/// MyClass.h
///
@interface MyClass : UIImageView
{
NSString *strTitle;
}
- (id) showTitle:(NSString *)titleText
+ (void) someMethod
@end

Здесь мы определили класс MyClass, который является наследником класса UIImageView. Класс имеет переменную strTitle и экземплярный метод showTitle.

На C# я бы то же самое записал так:

public class MyClass : UIImageView{
protected string strTitle;
public object showTitle(string titleText);
public static someMethod();
}

Здесь интересный тонкий момент, который, возможно, вам уже бросился в глаза — это странный знак «-» перед определением метода. Так в Objective-C определяется экземплярный метод, который можно использовать только после создания объекта данного класса. Знак «+» означает, что мы определяем метод класса или статический метод. Для обеспечения динамической типизации или определения типа во время выполнения применяется ключевое слово id, которое является указателем на «любой объект».

Реализация

Реализация осуществляется в (.m) файле и начинается с директивы @implementation и завершается директивой @end. Пример:

///
/// MyClass.m
///
#import "MyClass.h"

@implementation MyClass

- (id) showTitle:(NSString *)titleText
{

}

+ (void) someMethod
{

}

@end

Пример начинается с директивы #import, которая является аналогом директивы #include. Так же #import имеет дополнительную функциональность, которая гарантирует, что заголовочный файл будет включен всего один раз. Что является аналогом такого кода на C/C++:

#ifndef _uMainUnit_H_
#define _uMainUnit_H_
/// Your class difinishions here
#endif

Не знаю, нужны ли тут какие-либо комментарии ещё к реализации. По-моему понятно.

Свойства

Необходимость свойств в том, чтобы избавиться от написания огромного количества методов getter-ов/setter-ов. Язык Objective-C предлагает синтаксис для упрощения доступа к экземплярным переменным. Директива @property является частью выражения @interface и предназначена для организации доступа к экземплярной переменной. Сразу к примеру:

///
/// MyClass.h
///
@interface MyClass : UIImageView
{
NSString *titleText;
}
@property NSString *titleText;

@end

///
/// MyClass.m
///
#import "MyClass.h"

@implementation MyClass

@synthesize titleText;

@end

Определения свойства начинается с определения экземплярной переменной, далее используя директиву @property мы повторяем это определение. И завершаем директивой @synthesize в файле реализации класса @implementation. Вот в общем-то и всё, мы определили метод доступа к экземплярной переменной, который может читать и писать в переменную. По-умолчанию свойство имеет тип assign, но мы можем изменить это, указав соответствующий атрибут. Пример использования свойства:

NSString *titleText = [myClass titleText];
[myClass setTitleText:@"Hello World!"];
[myClass setTitleText:anotherTitleText];

Синтаксис «.»

Objective-C предлагает синтаксис «.», чтобы упростить использование свойств объекта. Ниже пример, который я привёл выше, но уже с использованием синтаксиса «.»:

NSString *titleText = myClass.titleText;
myClass.titleText = @"Hello World!";
myClass.titleText = anotherTitleText;

По-моему так проще, по крайней мере, мне как человеку из мира C++/C# — эта запись привычна и узнаваема. Так же синтаксис «.» может быть каскадирован, т.е. выражение myClass.Array.Length законно и применимо.

Это не всё по свойствам. Свойства так же могут включать атрибуты, которые меняют поведение свойства при присваивании и метод доступа к свойству. Свойства могут быть динамическими, т.е. добавляться во время выполнения, с помощью директивы @dynamic. И многое другое, но здесь и сейчас я не буду это рассматривать.

Категории и протоколы

Два последних элемента Objective-C, которых я бы хотел коснуться — категория и протокол.

Категоря

Про категорию общими словами.

Категория пришла в Objective-C из мира Smalltalk. Категория используется в случае, если вы хотите добавить поведение к классу без наследования от него. Т.е. категория позволяет расширить класс и добавить новые методы к нему и при этом не требуется исходных текстов класса, так же добавленные методы автоматически становятся доступными всем классам, унаследованным от изменяемого. Механизм, позволяющий расширять уже существующие классы (путем добавления новых методов, новые экземплярные переменные добавить таким образом нельзя), называется категориями. Как обычно, вы начинаете с создания пары файлов содержащих интерфейс @interface и реализацию @implementation.

Категория имеет свое имя, список методов и имя класса, который она расширяет. Описание категории имеет следующий вид:

#import "ClassName.h"@interface ClassName ( CategoryName )
methods declarations
@end

Реализация категории выглядит следующим образом:

#import "CategoryName.h"@implementation ClassName ( CategoryName )
methods bodies
@end

Больше в категории углубляться не буду.

Протокол

Язык Objective-C поддерживает полноценную работу протоколов. В языке С++ это чисто абстрактный класс, в C# — интерфейс. Протокол представляет только список описаний методов. Класс реализует протокол, если он содержит реализацию всех методов, описанных в протоколе.

Описание протокола:

@protocol ProtocolNamemethod declarations
@end

Пример более жизненный:

@protocol Shape
      - (void) draw: (Shape *) shape;
@end

Протокол может наследовать от произвольного количества других протоколов

@protocol Rectangle <Shape, Graphics, Serializable>

Возможно при описании класса задать не только родительский класс, но и набор протоколов:

@interface Square : Shape<Graphics, Persistance>

 

Рейтинг
( 1 оценка, среднее 5 из 5 )
Загрузка ...