Этот пост является продолжением моих 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 — это … забудь об этом, просто придерживайся настроек по умолчанию или готовься к худшему ?
Спасибо,
Лукаш