Метод вызова в текущем контроллере представления из App Delegate в iOS
У меня есть два контроллера вида (BuildingsViewController и RoomsViewController), которые используют функцию в делетете делегата с именем upload. Функция загрузки в основном выполняет HTTP-запрос, и если он успешный или неудачный, запускается uialertview. Это нормально работает.
Часть, с которой я борюсь, - это метод делегата connectionDidFinishLoading
. Мне нужно иметь возможность в основном обновлять текущий контроллер представления с помощью метода viewWillAppear
этого контроллера представления. Внутри функции viewWillAppear
каждого контроллера представления у меня есть код, который определяет кнопки на нижней панели инструментов.
Я хочу, чтобы кнопка "загрузить" на панели инструментов каждого контроллера представления автоматически удалялась при загрузке через делегат приложения.
Я пробовал делать [viewController viewWillAppear:YES]
из метода connectionDidFinishLoading
делегата приложения, но он никогда не вызывается.
Надеюсь, я достаточно ясен. Любая помощь приветствуется.
Спасибо.
Ответы
Ответ 1
Чтобы сделать обновление представления, не вызывайте viewWillAppear
, если представление уже отображается. Что вы хотите сделать, это следующее:
Когда метод ConnectionDidFinishLoading
запускается после уведомления
[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshView" object:nil];
В своем viewController
обратите внимание на это уведомление. Вы делаете это, добавляя этот код к методу init или viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshView:) name:@"refreshView" object:nil];
Теперь реализуем метод -(void)refreshView:(NSNotification *) notification
в вашем viewController
, чтобы управлять вашим представлением по своему вкусу.
Ответ 2
Если вы настроите iOS 4.0 и более поздние версии, вы можете использовать свойство window rootViewController
для получения текущего контроллера вида.
[window.rootViewController viewWillAppear];
Если вы хотите, чтобы ваше приложение запускалось в версиях до iOS 4.0, вы можете добавить переменную экземпляра в делегат приложения, чтобы запомнить, какой контроллер представлений называется методом upload
, имея контроллер, отправляемый как параметр.
- (void)upload:(UIViewController *)viewController {
self.uploadingViewController = viewController; // This is the property you add
...
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.uploadingViewController viewWillAppear];
self.uploadingViewController = nil;
}
Вы также должны рассмотреть возможность использования другого метода для перезагрузки кнопок, что-то вроде reloadButtons
, так как оно не связано с представлением, появляющимся в этом случае. Затем вы вызываете этот метод из viewWillAppear
.
Ответ 3
Шаг 1:
В вашем делете делегата .h файла вам нужно объявить такой протокол:
@protocol AppConnectionDelegate <NSObject>
@required
-(void)connectionFinished:(NSObject*)outObject;
@end
В том же файле добавьте ivar так:
id *delegate;
Объявите ivar как свойство:
@property (nonatomic, assign) id<AppConnectionDelegate> delegate;
В файле делегата приложения .m, синтезируйте ivar:
@synthesize delegate;
В файле делегата приложения .m, на connectionDidFinishLoading выполните:
if([self.delegate respondsToSelector:@selector(connectionFinished:)])
{
[self.delegate connectionFinished:objectYouWantToSend];
}
В вашем файле viewcontroller.h, реализуйте AppConnectionDelegate, импортировав ссылку на файл делегирования приложения:
#import "AppDelegate_iPhone.h" //if using iPhone
#import "AppDelegate_iPad.h" //if using iPad
В том же файле в конце первой строки объявления интерфейса выполните:
@interface AppDelegate_iPhone : AppDelegate_Shared <AppConnectionDelegate>
Объявите ivars соответственно:
AppDelegate_iPhone *appDelegate; //if using iPhone
AppDelegate_iPad *appDelegate; // if using iPad
В вашем файле viewcontroller.m в viewDidLoad() получите ссылку на делегата приложения, используя:
Если iPhone;
appDelegate = (AppDelegate_iPhone*)[[UIApplication sharedApplication] delegate];
Если iPad:
appDelegate = (AppDelegate_iPad*)[[UIApplication sharedApplication] delegate];
Затем установите viewcontroller как делегат в viewDidLoad(), выполнив:
appDelegate.delegate = self;
Теперь вам нужно просто реализовать метод connectionFinished в файле .m:
- (void)connectionFinished:(NSObject*)incomingObject
{
//Do whatever you want here when the connection is finished. IncomingObject is the object that the app delegate sent.
}
Теперь, когда вы вызываете соединение с делегатом connectionDidFinishLoading, контроллер уведомлений будет уведомлен.
[Лучше всего устанавливать appDelegate.delegate = nil, если вы закончили с помощью обратного вызова connectionFinished]
Это проверено и проверено. Если у вас есть вопросы, оставьте комментарий......
- EDIT -
Это надежная альтернатива NSNotification. Я использую оба в зависимости от требований. Процесс, который я использую для выбора между использованием NSNotification или обратным вызовом делегата с использованием протокола, просто:
Для уведомлений:
Один отправитель, несколько слушателей.
Нет никакой ссылки между отправителем и слушателем.
Не нужно отправлять сложные/множественные объекты
Для обратных вызовов делегатов с использованием протоколов:
Один отправитель, ограниченный (обычно 1) слушатель.
Возможна ссылка между отправителем и слушателем.
Сложные/множественные объекты должны быть отправлены (например, объекты ответа, которые необходимо отправить)
Я знаю, что отправка объектов возможна через уведомления, но я предпочитаю протоколы для этого.
--EDIT -
Ответ 4
Хуже всего то, что оба контроллера просмотра придерживаются простого протокола одного метода, который удалит эту кнопку и обновит представление. Затем в вашем методе connectionDidFinishLoading, поскольку вы знаете, что ваш контроллер представления должен придерживаться этого протокола, по вашему дизайну вы просто делаете что-то вроде
ViewController<MyProtocol> curView = (Get the current view controller somehow);
[curview refreshView];