从 iOS 中的 App Delegate 调用当前视图控制器中的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5873450/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling method in current view controller from App Delegate in iOS
提问by yupyupyup
I have two view controllers (BuildingsViewController and RoomsViewController) that both use a function within the App Delegate called upload. The upload function basically does an HTTP request, and if its successful or unsuccessful, triggers a uialertview. This is working fine.
我有两个视图控制器(BuildingsViewController 和 RoomsViewController),它们都使用 App Delegate 中称为上传的函数。上传功能基本上是做一个 HTTP 请求,如果它成功或不成功,就会触发一个 uialertview。这工作正常。
The part I'm struggling with is from within the app delegate's connectionDidFinishLoading
method. I need to be able to basically refresh the current view controller via perhaps viewWillAppear
method of that view controller. Inside the viewWillAppear
function of each view controller I have code which determines the buttons on the bottom toolbar.
我正在努力解决的部分来自应用程序委托的connectionDidFinishLoading
方法。我需要能够通过viewWillAppear
该视图控制器的方法基本上刷新当前视图控制器。在viewWillAppear
每个视图控制器的函数中,我有代码来确定底部工具栏上的按钮。
I want the "upload" button in the toolbar of each view controller to automatically be removed when the uploading is done via the app delegate.
我希望在通过应用程序委托完成上传时自动删除每个视图控制器工具栏中的“上传”按钮。
I've tried doing [viewController viewWillAppear:YES]
from within the connectionDidFinishLoading
method of the app delegate, but it never gets called.
我试过在应用程序委托[viewController viewWillAppear:YES]
的connectionDidFinishLoading
方法中做,但它永远不会被调用。
I hope I'm clear enough. Any help is greatly appreciated.
我希望我足够清楚。任何帮助是极大的赞赏。
Thanks.
谢谢。
回答by Cyprian
To do the refresh of the view do not call viewWillAppear
if the view is already displayed. What you want to do is the following:
viewWillAppear
如果视图已经显示,则不要调用刷新视图。您想要做的是以下内容:
When ConnectionDidFinishLoading
method is triggered post a notification
当ConnectionDidFinishLoading
方法被触发时发布通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshView" object:nil];
In your viewController
observe for this notification. You do it by adding this code to your init or viewDidLoad
method
在您viewController
观察此通知。您可以通过将此代码添加到您的 init 或viewDidLoad
方法中来实现
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshView:) name:@"refreshView" object:nil];
Now implement -(void)refreshView:(NSNotification *) notification
method in your viewController
to manage your view to your liking.
现在-(void)refreshView:(NSNotification *) notification
在您中实现方法以viewController
根据您的喜好管理您的视图。
回答by ughoavgfhw
If you are targeting iOS 4.0 and later, you can use the window's rootViewController
property to get the current view controller.
如果你的目标是 iOS 4.0 及更高版本,你可以使用 window 的rootViewController
属性来获取当前的视图控制器。
[window.rootViewController viewWillAppear];
If you want your application to run on versions prior to iOS 4.0, then you could add an instance variable to the application delegate to remember which view controller called the upload
method, having the controller send itself as a parameter.
如果您希望您的应用程序在 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;
}
You should also consider using a different method to reload the buttons, something like reloadButtons
, since it is not related to the view appearing in this case. You would then call that method from within viewWillAppear
.
您还应该考虑使用不同的方法来重新加载按钮,例如reloadButtons
,因为它与在这种情况下出现的视图无关。然后,您将从中调用该方法viewWillAppear
。
回答by Sid
Step 1:
第1步:
In your App Delegate .h file you need to declare a protocol like so:
在您的 App Delegate .h 文件中,您需要像这样声明一个协议:
@protocol AppConnectionDelegate <NSObject>
@required
-(void)connectionFinished:(NSObject*)outObject;
@end
In the same file, add an ivar like so:
在同一个文件中,像这样添加一个 ivar:
id *delegate;
Declare the ivar as a property:
将 ivar 声明为属性:
@property (nonatomic, assign) id<AppConnectionDelegate> delegate;
In the App Delegate .m file, synthesize the ivar:
在 App Delegate .m 文件中,合成 ivar:
@synthesize delegate;
In the App Delegate .m file, on connectionDidFinishLoading do:
在 App Delegate .m 文件中,在 connectionDidFinishLoading 上执行以下操作:
if([self.delegate respondsToSelector:@selector(connectionFinished:)])
{
[self.delegate connectionFinished:objectYouWantToSend];
}
In your viewcontroller's .h file, implement the AppConnectionDelegate by importing a reference to the app delegate file:
在您的视图控制器的 .h 文件中,通过导入对应用程序委托文件的引用来实现 AppConnectionDelegate:
#import "AppDelegate_iPhone.h" //if using iPhone
#import "AppDelegate_iPad.h" //if using iPad
In the same file, at the end of the first line of the interface declaration do:
在同一个文件中,在接口声明的第一行末尾执行:
@interface AppDelegate_iPhone : AppDelegate_Shared <AppConnectionDelegate>
Declare ivars accordingly:
相应地声明ivars:
AppDelegate_iPhone *appDelegate; //if using iPhone
AppDelegate_iPad *appDelegate; // if using iPad
In your viewcontroller's .m file in the viewDidLoad(), get a reference to your app delegate using:
在 viewDidLoad() 中的视图控制器的 .m 文件中,使用以下方法获取对应用程序委托的引用:
If iPhone;
如果iPhone;
appDelegate = (AppDelegate_iPhone*)[[UIApplication sharedApplication] delegate];
If iPad:
如果 iPad:
appDelegate = (AppDelegate_iPad*)[[UIApplication sharedApplication] delegate];
Then set the viewcontroller to be the delegate in viewDidLoad() by doing:
然后通过执行以下操作将 viewcontroller 设置为 viewDidLoad() 中的委托:
appDelegate.delegate = self;
Now you need to simply implement the connectionFinished method in the .m file:
现在您只需在 .m 文件中实现 connectionFinished 方法:
- (void)connectionFinished:(NSObject*)incomingObject
{
//Do whatever you want here when the connection is finished. IncomingObject is the object that the app delegate sent.
}
Now whenever your app delegate's connectionDidFinishLoading is called, the view controller will be notified.
现在,每当您的应用程序委托的 connectionDidFinishLoading 被调用时,都会通知视图控制器。
[It's a best practice to set appDelegate.delegate = nil if you're done using the connectionFinished callback]
[如果您使用 connectionFinished 回调完成,最好设置 appDelegate.delegate = nil]
This is tried and tested. If you have questions, leave a comment......
这是经过试验和测试的。如果您有任何问题,请发表评论......
--EDIT--
This is a robust alternative to NSNotification. I use both depending on the requirements. The process I use to decide between using NSNotification or a delegate callback using a protocol is simply:
--EDIT--
这是 NSNotification 的强大替代方案。我根据要求使用两者。我用来决定使用 NSNotification 还是使用协议的委托回调的过程很简单:
For notifications:
One sender, multiple listeners.
No reference possible between sender and listener.
Complex/multiple objects need not be sent
对于通知:
一个发送者,多个听众。
发送者和听众之间不可能有参考。
不需要发送复杂/多个对象
For delegate callbacks using protocols:
One sender, limited (usually 1) listeners.
A reference between sender and listener is possible.
Complex/multiple objects are to be sent (for example, response objects that need to be sent)
对于使用协议的委托回调:
一个发送者,有限的(通常是 1 个)监听者。
发送者和听众之间的引用是可能的。
要发送的复杂/多个对象(例如,需要发送的响应对象)
I know sending objects is possible through notifications but I prefer protocols for that.
--EDIT--
我知道可以通过通知发送对象,但我更喜欢协议。
- 编辑 -
回答by Dan F
Worse comes to worst, you can have both view controllers adhere to a simple one method protocol that will remove that button and refresh the view. Then in your connectionDidFinishLoading method, since you know your view controller must adhere to that protocol, by your design, you simply do something like
更糟糕的是,您可以让两个视图控制器都遵循一个简单的方法协议,该协议将删除该按钮并刷新视图。然后在您的 connectionDidFinishLoading 方法中,因为您知道您的视图控制器必须遵守该协议,所以根据您的设计,您只需执行类似的操作
ViewController<MyProtocol> curView = (Get the current view controller somehow);
[curview refreshView];