Программирование на Objective-C 2.0
Шрифт:
Первая программа iPhone в этой главе начиналась с шаблона проекта типа Window-Based. Наша небольшая работа, связанная с пользовательским интерфейсом (Ш), была выполнена непосредственно в контроллере приложения (с помошью класса AppDelegate). Такой подход не рекомендуется для разработки приложений с насыщенным пользовательским интерфейсом. Класс AppDelegate обычно используется только для обработки изменений, относящихся к состоянию самого приложения, например, к окончанию запуска приложения или к его завершению.
Рис. 21.21 Ввод операции
Контроллер представлений (view controller), реализованный с помощью класса UlViewController, подходит именно для действий, относящихся к Ш, таких как отображение текста, реагирование на нажатие кнопки или вывод другого представления на экране iPhone.
Разработку
Рис. 21.22. Результат умножения двух дробей
При создании проекта вы увидите, что на этот раз используются два шаблона классов. FractionCalculatorAppDelegate.il и Fraction_CalсuIatorАрpDelegate.m определяют для нашего проекта класс контроллера приложения, a Fraction CalculatorViewController.h и Fraction CalculatorViewController.m определяют класс контроллера представлений. Как говорилось выше, вся наша работа будет выполнена именно во втором классе.
Начнем с класса контроллера приложения. Он содержит две переменные экземпляра: одну для ссылки на окно iPhone и вторую — для контроллера представлений. Обе переменные заданы вХсобе. Вам не потребуется вносить никакие изменения в .h-файл и .m-файл контроллера приложения.
Файл секции interface Fraction_CalculatorApp Delegate показан в программе 21.2.
Программа 21.2. Interface-файл Fraction_CalculatorAppDelegate.h #import <UIKit/UIKit.h> @class Fraction_CalculatorViewController; @interface FractionCalculatorAppDelegate : NSObject <UIApplicationDelegate> { IBOutlet UlWindow *window; IBOutlet Fraction CalculatorViewController *viewController; } @property (nonatomic, retain) UlWindow *window; @property (nonatomic, retain) Fraction_CalculatorViewController *viewController; @end
Переменная экземпляра UlWindow window предназначена для той же цели, что и в первой программе: она представляет окно iPhone. Переменная экземпляра Fraction_CalculatorViewController используется для контроллера представлений, который будет управлять всем взаимодействием с пользователем и выводом на дисплей. В файле секции implementation для этого класса мы реализуем всю работу, связанную с этими задачами.
В программе 21.2 показан implementation-файл для класса контроллера приложения. Как говорилось выше, мы не будем делать никакой работы в этом файле (в отличие от программы 21.1); вся работа передается контроллеру представлений. Таким образом, этот файл показан так, как он генерируется Xcode при создании нового проекта.
Программа 21.2. Implementation-файл Fraction_CalculatorAppDelegate.m #import "FractionCalculatorAppDelegate.h" #import "Fraction CalculatorViewController.h" @implementation Fraction_CalculatorAppDelegate @synthesize window; @synthesize viewController; -(void)applicationDidFinishLaunching:(UIApplication *(application ( // Место переопределения для настройки после запуска приложения [window addSubview:viewController.view]; [window makeKeyAndVisible]; -(void)dealloc { [viewController release]; [super deallocj; @end Определение контроллера представлений
Теперь мы напишем код для класса контроллера представлений Fraction CalculatorViewController. Начнем с файла секции interface. Он показан в про грамме 21.2.
Программа 21.2. Interface-файл Fraction_CalculatorViewController.h #import <UIKit/UIKit.h> #import "Calculator.h" @interface Fraction_CalculatorViewController : UlViewController { UlLabel *display; char op; int currentNumber; NSMutableString *displaystring; BOOL firstOperand, isNumerator; Calculator *myCalculator; } @property {nonatomic, retain) IBOutlet UlLabel *display; @property (nonatomic, retain) NSMutableString *displaystring; -(void) processDigit: (int) digit; -(void) processOp: (char) op; -(void) storeFracPart; // Числовые клавиши -(IBAction) clickDigit; (id) sender; // Клавиши арифметических операций -(IBAction) clickPlus: (id) sender; -(IBAction) clickMinus: (id) sender; -(IBAction) clickMultiply: (id) sender; -(IBAction) clickDivide: (id) sender; // Другие клавиши -(IBAction) clickOver: (id) sender; -(IBAction) clickEquals: (id) sender; -(IBAction) clickClear: (id) sender; @end
У нас имеются служебные переменные для создания дробей (currentNumber, firstOperand и isNumerator) и для создания выводимой строки (displayString). Объект типа Calculator (myCalculator) выполняет конкретные вычисления между двумя дробями. Мы выполним привязку метода с именем clickDigit: для обработки нажатий цифровых клавиш 0-9. И, наконец, мы определяем методы для хранения операции, которая должна быть
выполнена (clickPlus:, clickMinus:, clickMultiply:, clickDivide:), выполняя сами вычисления при нажатии клавиши = (clickEquals:), сброс текущей операции (clickClear:) и отделение числителя от знаменателя при нажатии клавиши Over (clickOver:). Несколько методов (processDigit:, processOp: и StoreFracPart) определяются для этих задач как вспомогательные средства.В программе 21.2 показан файл секции implementation для этого класса контроллера.
Программа 21.2. Implementation-файл Fraction_CalculatorViewController.m #import «Fraction_CalculatorViewController.h» @implementation FractionCalculatorViewController @synthesize display, displayString; -(void) viewDidLoad { // Место переопределения для настройки после запуска приложения firstOperand = YES; isNumerator = YES; self.displayString = [NSMutableString stringWithCapacify: 40]; myCalculator = [[Calculator alloc] init]; -(void) processDigit: (int) digit { currentNumber = currentNumber * 10 + digit; [displayString appendString: [NSString stringWithFormat: <a>"%i\ digit]]; [display setText: displayString]; -(IBAction) clickDigit:(id)sender { int digit = [sender tag]; [self processDigit: dig it]; } -{void) processOp: (char) theOp { NSString *opStr; op = theOp; switch (theOp) { case opStr = + "; break; case opStr = -"; break; case *': opStr = <@" ? "; break; case opStr = break; } [self storeFracPart]; firstOperand = NO; isNumerator = YES; [displaystring appendString: opStr); [display setText: displaystring]; -(void) storeFracPart { if (firstOperand) { if (isNumerator) { myCalculator.operandl.numerator = currentNumber; myCalculator.operandl .denominator = 1; // e g. 3*4/5 = ) else myCalculator.operandl.denominator = currentNumber; } else if (isNumerator) { myCalculator.operand2.numerator = currentNumber; myCalculator.operand2.denominator = 1; // e.g. 3/2*4 = } else { myCalculator.operand2.denominator = currentNumber; firstOperand = YES; } currentNumber = 0; } -(IBAction) clickOver: (id) sender { [self storeFracPart]; isNumerator = NO; [displaystring appendString: @"/"]; [display setText: displaystring]; } // Клавиши арифметических операций -(IBAction) clickPlus: (id) sender { [self processOp: } -(IBAction) clickMinus: (id) sender { [self processOp: } -(IBAction) clickMultiply: (id) sender { [self processOp: } -(IBAction) clickDivide: (id) sender { [self processOp: У]; ) // Другие клавиши -(IBAction) clickEquals: (id) sender { [self storeFracPart]; [myCalculator performOperation: op]; [displaystring appendString: = "]; [displaystring appendString: [myCalculator.accumulator convertToString]]; [display setText: displayString]; currentNumber = 0; isNumerator = YES; firstOperand = YES; [displayString setString: (§>""]; } -(IBAction) clickClear: (id) sender { isNumerator = YES; firstOperand = YES; currentNumber = 0; [myCalculator clear]; [displayString setString: @'"]; [display setText: displayString]; -(void)dealloc { [myCalculator dealloc]; [super dealloc]; } @end
Окно калькулятора пока содержит только одну метку, как в предыдущем приложении, и мы по-прежнему называем се display. По мерс того, как пользователь вводит число пифра за цифрой, мы должны формировать это число. Переменная currentNumber содержит накапливаемое число, а BOOL-переменные firstOperand и isNumerator следят за тем, какой операнд введен (первый или второй), и что представляет этот операнд — числитель или знаменатель.
При нажатии числовой клавиши идентифицирующая информация будет передаваться методу clickDigit:, чтобы указать, какая числовая клавиша была нажата. Для этого атрибуту клавиши с именем tag (с помощью средства Inspector в Interface Builder) присваивается соответствующее значение каждой числовой клавиши. В данном случае нам нужно присвоить tag соответствующую цифру. Например, для клавиши с меткой 0 tag будет присвоено значение 0, для клавиши с меткой 1 — значение 1, и т.д. При последующей отправке сообщения tag параметру sender, который передается методу clickDigit:, мы считываем значение тега клавиши. Это происходит в методе clickDigit:, как показано ниже. -(IBAction) clickDigit:(id)sender { int digit = [sender tag]; [self processDigitrdigit]; }
В программе 21.2 намного больше клавиш, чем в первом приложении. Наиболее сложной частью в implementation-файле контроллера представлений является формирование и отображение дробей. Как говорилось выше, при нажатии числовой клавиши от 0 до 9 выполняется action-метод clickDigit:. Этот метод вызывает метод processDigit:, который помещает цифру в конец числа, формируемого в переменной currentNumber. Этот метод также добавляет цифру в текущую строку отображения, которая поддерживается в переменной displaystring, и обновляет отображение. -(void) processDigit: (int) digit ( currentNumber = currentNumber * 10 + digit; [displaystring appendString: [NSString stringWithFormat: @"%i", digit]]; [display setText: displaystring];}