应用程序激活时刷新视图中的竞争条件

发布于 2024-11-05 00:11:16 字数 1334 浏览 2 评论 0原文

在 Facebook 的 iPhone 应用程序上,每次应用程序激活时,新闻源都会刷新。我想做类似的事情,但我担心竞争条件。我的应用程序的一般引导如下:

UIApplicationDelegate

- (void)applicationDidFinishLaunching:(UIApplication*)application
{
  [window addSubview:[self.navigationController view];
  [window makeKeyAndVisible];
}

- (void)applicationDidBecomeActive:(UIApplication*)application
{
  [rootViewController refresh];
}

RootViewController

#pragma mark custom

- (void)refresh
{
  if (self.newsFeedModel == nil) {
   self.newsFeedModel = [[NewsFeedModel alloc] initWithDelegate:self];
  }
  [self.newsFeedModel request];
}

#pragma mark UIViewController

- (void)viewDidLoad
{
  // initialize the table
  // add subviews and whatnot
}

#pragma mark NewsFeedDelegate

- (void)newsFeedSucceeded:(NSMutableArray*)feed
{
  // reload table view with new feed data
}

在各处撒上 NSLog 后,我确定操作顺序为:

  1. applicationDidFinishLaunching
  2. applicationDidBecomeActive
  3. 刷新
  4. viewDidLoad
  5. newsFeedSucceeded

请注意在加载根视图之前如何调用刷新。当我们忙于查询服务器时,根视图会加载。当服务器响应时,根视图将填充提要。这在大多数情况下都有效,因为网络操作需要很长时间。但是,如果网络操作完成的速度快于加载视图的速度,那么我将尝试在加载视图之前构建新闻源。这会很糟糕。解决这种竞争状况的最佳 Cocoa Touch 实践是什么?我只是设置一堆标志来确定我们所处的状态,并根据状态刷新新闻提要,但我想知道 Cocoa Touch 中是否有内置事件来为我处理这个问题。

On Facebook's iPhone app, the news feed refreshes every time the app becomes active. I would like to do something similar, but I'm concerned about a race condition. The general bootstrapping of my app is as follows:

UIApplicationDelegate

- (void)applicationDidFinishLaunching:(UIApplication*)application
{
  [window addSubview:[self.navigationController view];
  [window makeKeyAndVisible];
}

- (void)applicationDidBecomeActive:(UIApplication*)application
{
  [rootViewController refresh];
}

RootViewController

#pragma mark custom

- (void)refresh
{
  if (self.newsFeedModel == nil) {
   self.newsFeedModel = [[NewsFeedModel alloc] initWithDelegate:self];
  }
  [self.newsFeedModel request];
}

#pragma mark UIViewController

- (void)viewDidLoad
{
  // initialize the table
  // add subviews and whatnot
}

#pragma mark NewsFeedDelegate

- (void)newsFeedSucceeded:(NSMutableArray*)feed
{
  // reload table view with new feed data
}

After sprinkling NSLog everywhere, I determined the order of operations to be:

  1. applicationDidFinishLaunching
  2. applicationDidBecomeActive
  3. refresh
  4. viewDidLoad
  5. newsFeedSucceeded

Notice how refresh is called before the root view has been loaded. While we're busy querying the server, the root view loads. When the server responds, the root view is populated with the feed. This works in most cases because the network operation takes a long time. However, if the network operation finishes faster than view can be loaded, then I will be attempting to construct the news feed before the view has been loaded. This would be bad. What is the best Cocoa Touch practice for solving this race condition? I would just set a bunch of flags to determine what state we're in and refresh the news feed depending on the state, but I'm wondering if there were built in events in Cocoa Touch to handle this for me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情深已缘浅 2024-11-12 00:11:16

我想你想看看 applicationWillEnterForeground: 相反。

applicationDidBecomeActive:可以在您的应用程序仍在前台运行时调用。例如,如果您的应用程序位于前台时收到一条短信并且用户将其关闭,则 applicationDidBecomeActive: 将被调用。

您可以使用 NSNotificationCenter 订阅 RootViewController 中的 UIApplicationWillEnterForegroundNotification 事件。我会在 RootViewController initWithNibName: 或您使用的任何 init 方法中执行此操作。

现在你只需要在两个地方调用刷新即可。在 viewDidLoad 结束时一次,并在调用 applicationWillEnterForeground: 时再次进行。

这应该可以解决您的竞争条件问题。由于 RootViewController 在知道可以这样做时正在处理它自己的刷新。

根视图控制器

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    }
    return self;
}

- (void)viewDidLoad
{
    // initialize the table
    // add subviews and whatnot
    [self refresh];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self refresh];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

I think you want to take a look at applicationWillEnterForeground: instead.

applicationDidBecomeActive: can be called while your app is still running in the foreground. For instance if a text message comes while your app is in the foreground and the user dismisses it, applicationDidBecomeActive: will get called.

You can subscribe to the UIApplicationWillEnterForegroundNotification event in your RootViewController using NSNotificationCenter. I would do this in RootViewController initWithNibName: or whichever init method you are using.

Now you just need to call refresh in 2 places. Once at the end of viewDidLoad and again whenever applicationWillEnterForeground: is called.

This should solve your race condition problem. Since RootViewController is handling it's own refreshing when it knows it is ok to do so.

RootViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    }
    return self;
}

- (void)viewDidLoad
{
    // initialize the table
    // add subviews and whatnot
    [self refresh];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self refresh];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文