Общий формат для объявления объекта в Objective-C следующий:
1 |
имяКласса *var1, *var2, ...; |
Здесь определяются переменные var1, var2, … как объекты из класса имяКласса. Отметим, что это объявление переменных-указателей, при котором не выделяется пространство для конкретных данных, содержащихся в каждом объекте.
В объявлении:
1 |
Fraction *myFract; |
определяется myFract как объект класса Fraction или, точнее, как указатель на этот объект. Чтобы фактически выделить пространство для структуры данных класса Fraction, нужно вызвать обычно alloc или новый метод для этого класса, например:
1 |
myFract = [Fraction alloc]; |
В результате для объекта типа Fraction будет выделен достаточный объекм памяти и возвращен указатель на этот объект, который будет присвоен переменной myFract.
Переменную myFract часто называют объектом или экземпляром класса Fraction. Если метод alloc определен в корневом объекте, всем переменным экземпляра нового выделяемого объекта присваивается значение 0.
Но это не означает, что объект инициализирован должным образом. Прежде чем использовать этот объект, для него должен быть вызван какой-либо метод инициализации, например init.
Поскольку переменная myFract была объявлена явным образом как объект из класса Fraction, она называется переменной со статическим контролем типа.
Компилятор может проверять применение переменных со статическим контролем типа на согласованность с определением класса с точки зрения правильности использования методов, а также типов их аргументов и возвращаемых значений.
Объявление объекта с типом id:
1 |
id <протокол,...> var1, var2, ...; |
Здесь объявляются переменные var1, var2, … как объекты из неопределенного класса, который подчиняется протоколам, перечисленным в угловых скобках. Список протоколов не является обязательным.
Переменным типа id можно присваивать объекты из любого класса, и наоборот. Если указаны один или несколько протоколов, компилятор проверяет что методы, используемые из перечисленных протоколов для любой из объявленных переменных, используются соответствующим образом, то есть в соответствии с типами аргументов и возвращаемых значений для методов, объявленных в формальном протоколе.
Например ниже:
1 2 3 |
id <MathOps> number; ... result = [number add: number2]; |
компилятор проверяет, определяется ли метод add: в протоколе athOps. Если да, то компилятор проверяет для этого метода согласованность с типами аргументов и возвращаемого значения. Например, если метод add: принимает целый аргумент, а вы передаете ему объект класса Fraction, то компилятор выводит соответствующее сообщение.
Система следит за классом, которому принадлежит каждый объект, поэтому на этапе выполнение она может определить класс объекта и затем выбрать для вызова подходящий метод. Эти две процедуры называются соответственно динамическим контролем типов(dynamic typing) и динамическим связыванием (dynamic binding).