Этот пост является продолжением моих 3 предыдущих постов:
- 10 самых полезных советов для разработчиков iPhone (часть 1)
- 10 самых полезных советов для разработчиков iPhone (часть 2)
- 10 самых полезных советов для iPhone (часть 1)
Давай покатимся.
6. Восстановление состояния приложения.
Платформа Three20 может восстанавливать контроллеры представления, если вы придерживаетесь
TTNavigator
и передаете все данные в качестве параметров URL. Но представьте, что у вас есть сложный объект для передачи между представлениями, например, критерии поиска, или вы хотите сохранить электронную почту последнего успешного входа в систему. Вы можете объединить функциональность контроллеров представления Three20 с NSUserDefaults
классом Apple
.
Когда приложение запускается и завершается, UIApplicationDelegate
вызываются соответствующие
методы. Эти методы являются идеальными местами для восстановления / сохранения состояния приложения. Чтобы проиллюстрировать эту ситуацию, взгляните на следующий код:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // restore app's state from NSUserDefaults NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSData *data = [defaults objectForKey:@"searchCriteria"]; NSKeyedArchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; SearchCriteria *searchCriteria = [[SearchCriteria alloc] initWithCoder: unarchiver]; [DataContainerService setSearchCriteria:searchCriteria]; NSString *lastSuccessfulLoginEmailAddress = [defaults objectForKey:@"lastSuccessfulLoginEmailAddress"]; [DataContainerService setLastSuccessfulLoginEmailAddress:lastSuccessfulLoginEmailAddress]; [TTStyleSheet setGlobalStyleSheet:[[[DefaultStyles alloc] init] autorelease]]; TTNavigator* navigator = [TTNavigator navigator]; navigator.persistenceMode = TTNavigatorPersistenceModeAll; navigator.supportsShakeToReload = YES; navigator.opensExternalURLs = YES; TTURLMap* map = navigator.URLMap; [map from:@"*" toViewController:[TTWebController class]]; [map from:@"tt://tabBar" toSharedViewController:[TabBarController class]]; [map from:@"tt://search" toSharedViewController:[SearchViewController class]]; [map from:@"tt://map" toSharedViewController:[MapViewController class]]; if (![navigator restoreViewControllers]) { [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://tabBar"]]; } return YES; } - (void)applicationWillTerminate:(UIApplication *)application { SearchCriteria *searchCriteria = [DataContainerService searchCriteria]; NSMutableData *data = [NSMutableData new]; NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; [propertySearchCriteria encodeWithCoder:encoder]; [encoder finishEncoding]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:data forKey:@"searchCriteria"]; [data release]; NSString *lastSuccessfulLoginEmailAddress = [DataContainerService lastSuccessfulLoginEmailAddress]; [defaults setObject:lastSuccessfulLoginEmailAddress forKey:@"lastSuccessfulLoginEmailAddress"]; }
7. Используйте sizeToFit
Многие элементы управления пользовательского интерфейса (например
UILabel
,
UIButton
) предлагают функцию автоматического изменения размера. Это можно использовать при динамическом заполнении текста из JSON и т. Д. Чтобы изменить размер метки, просто вызовите
[label sizeToFit]
метод, и вы дома.
8. Динамические кнопки со свойством userInfo
Иногда, в зависимости от дизайна представления, вы можете получить множество кнопок, выполняющих одно и то же действие, но с другим объектом.
Например, представьте список отделений для применения в больнице. Это как X динамически создаваемых кнопок с именами пациентов, когда вы нажимаете кнопку, появляется представление с данными пациента. Обычно вы назначаете всем кнопкам одно и то же действие, и внутри него вы бы перебирали коллекцию кнопок, находили индекс затронутой кнопки, извлекали пациента из коллекции пациента, а затем на основании идентификатора пациента открывали представление сведений.
Это может быть упрощено, если вы расширяете UIButton
и добавляете
userInfo
свойство , коллекции для пациентов и кнопок не требуются
. Взглянем:
@interface UserInfoButton : UIButton { id _userInfo; } @property (nonatomic, assign) id userInfo; @end @implementation UserInfoButton @synthesize userInfo = _userInfo; @end
И ввиду контроллера:
for (Patient *patient in patients) { UserInfoButton *button = [[UserInfoButton alloc] initWithFrame:CGRectMake(0, offset, 155, 15)]; [button addTarget:self action:@selector(navigateToPatientDetailsView:) forControlEvents:UIControlEventTouchUpInside]; button.userInfo = patient; ... } and in action: -(void) navigateToPatientDetailsView: (UserInfoButton*) sender { TTOpenURL([NSString stringWithFormat:@"tt://patient/%d", ((Patient*)sender.userInfo).patientId]); }
Просто, не правда ли?
9. Используйте JSON для обмена данными.
Если вы обмениваетесь данными с внешними веб-сервисами, гораздо лучше использовать RESTful Web Services и JSON.
Зачем? Существует две основные причины:
1. Веб-службы RESTful легко кэшируются как на стороне клиента, так и на стороне сервера.
2. Формат данных JSON очень компактен по сравнению с довольно подробным XML.
Существует множество библиотек JSON для Objective-C. Просто забери свой любимый.
10. Остерегайтесь автоматически выпущенных объектов, отпустите объект сразу после того, как вы закончите с ними работать
Автоподводимые объекты — это кошмары. Почему вы должны остерегаться их? Потому что они могут быть автоматически освобождены в любое время (если вы не сохраните их). Вы не обнаружите эту проблему при разработке приложения, она будет обнаружена, когда в системных или пользовательских приемочных тестах ваше приложение будет работать дольше нескольких секунд.
В большинстве случаев очень легко узнать, был ли объект, возвращенный методом, автоматически освобожден или нет, так как Apple имеет соглашение об именах, которое говорит вам об этом. Если метод создает объект и его имя начинается с имени объекта (без префиксов UI или NS), это означает, что возвращаемый объект автоматически освобождается. Примеры:
[NSString stringWithFormat:@"I'm just an example: %@", text]; [UIImage imageNamed:pathToImage];
Также будьте внимательны, выпуская все объекты, которые вы создаете. Лучшее место для раскрытия свойств —
-(void)dealloc
метод. Локальные переменные должны быть освобождены в тот самый момент, когда они больше не нужны.
И наконец, помните, что массивы сохраняют ссылки. Следующий исходный код:
NSMutableArray *array = [NSMutableArray new]; for (NSUInteger i = 0; i < 5; i++) { NSString *newString = [[NSString alloc] initWithFormat: @"I'm string no %@", (i+1)]; NSLog(@"Before adding string to array '%@', its retain count is %d", newString, [newString retainCount]); [array addObject: newString]; NSLog(@"After adding string to array '%@', its retain count is %d", newString, [newString retainCount]); } NSString *lastInsertedString = [array lastObject]; [array release]; NSLog(@"Last object in array is '%@', its retain count is %d", [lastInsertedString retainCount]); Results in a memory leak: Before adding string to array 'I'm string no 1', its retain count is 1 After adding string to array 'I'm string no 1', its retain count is 2 Before adding string to array 'I'm string no 2', its retain count is 1 After adding string to array 'I'm string no 2', its retain count is 2 Before adding string to array 'I'm string no 3', its retain count is 1 After adding string to array 'I'm string no 3', its retain count is 2 Before adding string to array 'I'm string no 4', its retain count is 1 After adding string to array 'I'm string no 4', its retain count is 2 Before adding string to array 'I'm string no 5', its retain count is 1 After adding string to array 'I'm string no 5', its retain count is 2 Last object in array is 'I'm string no 5', its retain count is 1
Что вы должны сделать, это добавить
[newString release];
внутри цикла, чтобы освободить вновь созданные объекты сразу после их добавления в массив. Затем, если вы повторно запустите вышеуказанный код, последняя строка приведет к плохому доступу. Зачем? потому что
lastInsertedString
объект был наконец выпущен!
Бонусный совет: оценки
Map Kit Map Kit … При оценке чего-либо, связанного с Map Kit, умножьте его на 2 или даже на 3, если вы планируете выполнить полную настройку выносок, контактов, сгруппированных контактов, упаковки / распаковки контактов, интеграции GPS и т. Д. Map Kit — это … забудь об этом, просто придерживайся настроек по умолчанию или готовься к худшему ?
Спасибо,
Лукаш