Программирование на Objective-C 2.0
Шрифт:
Локальные переменные не имеют начального значения по умолчанию, поэтому вы должны присвоить им некоторое значение, прежде чем использовать их. Трем локальным переменным в методе reduce присваиваются значения до того, как они используются, поэтому здесь не возникает никакой проблемы. В отличие от переменных экземпляра (которые сохраняют свои значения при вызовах методов), эти локальные переменные не имеют памяти, и после возврата из метода значения этих переменных исчезают. Каждый раз, когда происходит вызов метода, выполняется инициализация каждой локальной переменной, определенной
Имена, которые вы используете для обозначения аргументов метода, тоже являются локальными переменными. При выполнении метода любые аргументы, передаваемые методу, копируются в эти переменные. Поскольку метод работает с копией аргументов, он не может изменить исходные значения, переданные методу. Предположим, у нас есть метод с именем calculate:, определенный следующим образом: -(void) calculate: (double) х { х *= 2; }
Предположим также, что для его вызова использовано выражение: [myData calculate: ptVal];
При вызове метода calculate значение, содержащееся в переменной ptVal, копируется в локальную переменную х. Поэтому изменение х внутри calculate: не оказывает никакого влияния на значение переменной ptVal — только копия ее значения сохраняется внутри х.
Для аргументов, которые являются объектами, вы можете изменять переменные экземпляра, хранящиеся в этом объекте. Об этом рассказывается в следующей главе. Ключевое слово static
Чтобы локальная переменная сохраняла свое значение при нескольких вызовах метода, поместите ключевое слово static перед объявлением переменной. В следующей строке целая переменная hitCount объявляется как статическая переменная. static int hitCount = 0;
В отличие от других локальных переменных, статическая переменная имеет начальное значение 0, поэтому приведенная выше инициализация является излишней. Кроме того, статические переменные инициализируются только один раз, в начале выполнения программы, и сохраняют свои значения при нескольких вызовах метода.
Приведенная ниже последовательность строк может содержаться внутри метода showPage, который должен следить за числом своих вызовов (в данном случае — число выведенных страниц). -(void) showPage { static int pageCount = 0; ++pageCount;
Локальной статической переменной присваивается значение 0 только один раз (при запуске программы), а затем это значение сохраняется при всех последующих вызовах метода showPage.
Если pageCount задана как локальная статическая переменная, то в ней подсчитывается число страниц, выведенных всеми объектами, которые вызвали метод showPage.
Если pageCount задана как переменная экземпляра, то в ней подсчитывается число страниц, выведенных каждым объектом, поскольку каждый объект будет содержать свою собственную копию pageCount.
Доступ к статическим или локальным переменным может выполняться только из метода, где они определены, поэтому даже статическая переменная pageCount доступна только внутри showPage. Чтобы сделать эту переменную доступной другим методам, нужно объявить ее вне объявления любого метода (обычно это делают в начале файла implementation),
После этого любой метод экземпляра или класса сможет выполнять доступ к переменной pageCount. Области действия переменных подробно рассматриваются в гл. 10.
Итак, мы можем вставить код метода reduce в файл секции implementation Fraction.m. Не забудьте объявить метод reduce в файле секции interface Fraction.h.
После этого вы можете проверить метод в программе 7.4. #import «Fraction.h» int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *aFraction = [[Fraction alloc] init]; Fraction *bFraction = [[Fraction alloc] init]; [aFraction setTo: 1 over: 4]; // set 1st fraction to 1/4 [bFraction setTo: 1 over: 2]; // set 2nd fraction to 1/2 [aFraction print]; NSLog (@"+"); [bFraction print]; NSLog (@"="); [aFraction add: bFraction]; // сокращение дроби после сложения и вывод результата [aFraction reduce]; [aFraction print]; [aFraction release]; [bFraction release]; [pool drain]; return 0; }
Вывод программы 7.4 1/4 + 1/2 3/4
Этот результат, несомненно, лучше! 7.6. Ключевое слово self
В программе 7.4 мы решили сокращать дробь вне метода add:. Мы могли бы делать это и внутри метода add:. Но как мы сможем указать методу reduce дробь, для которой нужно выполнить сокращение? Мы знаем, как непосредственно идентифицировать по имени переменные экземпляра внутри метода, но не знаем, как непосредственно идентифицировать получателя сообщения.
Вы можете использовать ключевое слово self для ссылки на объект, который является получателем текущего метода. Если внутри метода add: добавить [self reduce]; `
то метод reduce будет применен к объекту Fraction, который был получателем метода add:, а это нам как раз и нужно. Далее вы увидите, насколько полезным может оказаться ключевое слово self. В методе add: оно применяется следующим образом. -(void) add: (Fraction *) f { // Для сложения двух дробей: // a/b + c/d = ((a*d) + (b*c)) / (b * d) numerator = (numerator * [f denominator]) + (denominator * [f numerator]); denominator = denominator * [f denominator]; [self reduce]; }
После сложения будет выполнено сокращение дроби. 7.7. Выделение памяти и возврат объектов из методов
Мы уже говорили, что метод add: изменяет значение объекта, который получает сообщение. Мы создадим новую версию метода add:, который будет вместо этого создавать новый объект типа fraction для сохранения результата сложения. В этом случае мы должны возвращать новый объект типа Fraction отправителю сообщения. Ниже приводится определение этого нового метода add:. -(Fraction *) add: (Fraction *) f { // Для сложения двух дробей: // a/b + c/d = ((a*d) + (b*c)) / (b * d) // В result будет сохраняться результат сложения Fraction *result = [[Fraction alloc] init]; iint resultNum, resultDenom; resultNum = numerator * f.denominator + denominator * f.numerator; resultDenom = denominator * f.denominator; [result setTo: resultNum over: resultDenom]; [result reduce]; return result; }