UIActivity视图控制器在iPad上无法关闭

9

我有一个UIActivity子类,它创建自己的activityViewController

- (UIViewController *)activityViewController {
    WSLInProgressViewController* progressView = [[[WSLInProgressViewController alloc] init] autorelease];
    progressView.message = [NSString stringWithFormat:NSLocalizedString(@"Posting to %@...",@"Posting to..."),
                        self.activityType];

    return progressView;
}

我已经添加了一个完整的在GitHub上的复现


根据文档,您不应手动解除此操作。相反,在调用activityDidFinish:时,操作系统会执行此操作。在iPhone上运行时,这很好用。
当我说“工作”时,我期望的事件顺序是(并且在iPhone上看到):
1. 显示UIActivityViewController 2. 用户按下我的自定义活动 3. 我的视图控制器出现 4. 我调用activityDidFinish: 5. 我的自定义视图控制器被解除 6. UIActivityViewController也被解除
但是,当我在iPad模拟器上运行此相同代码时-唯一的区别是我将UIActivityViewController放在弹出窗口中,因为文档说你应该这样做-activityViewController从未解除。
正如我所说,这是没有弹出窗口的代码在iPhone上工作,我已经逐步执行了代码,所以我知道activityDidFinish:正在被调用。
我发现这个雷达谈论了iOS6 beta 3中的同样问题,但这似乎是如此基本的功能,以至于我怀疑我的代码有bug而不是操作系统(还要注意的是它与Twitter和Facebook功能正常工作!)。

我是否漏掉了什么?当在UIPopoverViewController中运行时,我需要在activityViewController中做一些特殊的事情吗?在iPad上,这个“流程”是否应该不同?


你是如何关闭UIPopoverViewController的?从以往经验来看,你需要通过调用 [myPopoverControler dismissPopoverAnimated]; 显式地关闭弹出窗口本身。 - Mitchell Currie
你有为这个问题想出解决方案吗?它看起来是一个严重的 bug。基本上,这意味着在 iPad 上实现 activityViewController 的自定义 UIActivity 是无用的。 - matt
1
@matt 下面的被接受的答案是我见过的最好的。我为“不消失”的错误提出了Radar 12545554,为“以模态方式显示”提出了12545600。如果你有机会,请帮我转发一下。它们两个仍然没有解决。对于我的应用程序,我最终没有使用activityViewController - Stephen Darlington
感谢@StephenDarlington - 我确实提交了一个关于这个问题的错误报告。您下面接受的答案只能工作一次,而不是第二次,如果您检查涉及的各种类的dealloc,您会发现在幕后发生了严重的内存管理错误。 - matt
8个回答

8
自动解雇只在您的“activity”控制器直接呈现时才会出现,而不是包含在其他任何东西中。因此,在显示弹出窗口之前,请添加完成处理程序进行包装。
activity.completionHandler = ^(NSString *activityType, BOOL completed){
   [self.popup dismissPopoverAnimated:YES];
};

然后你就会做得很好了。


1
是的,那就解决了。(它仍然显示为模态表单而不是弹出式窗口,但这是另一个问题...) - Stephen Darlington
1
这似乎只是延迟了问题。第二次选择自定义活动时,应用程序会崩溃。据我所知,第一个UIActivityViewController和UIViewController泄漏了,当您尝试创建第二个时,它会因为某些过期数据而崩溃。有人有什么想法如何解决这个问题吗? - ragfield
@ragfield 你说得对。这种行为在我的测试应用程序中也表现出来了。我已经提交了一份关于此事的报告。目前还没有苹果方面的回应。 - Stephen Darlington
还可以尝试在activityViewController和自定义的UIActivity中记录deallocactivityViewController上会被调用两次,而UIActivity对象则存在内存泄漏。这非常不对。在iPad上可能存在管理方面的问题。 - matt
这只是对真正问题的临时修补/解决方案。请参见eploko下面的答案了解真正的根本原因。根据Apple的文档,您不应直接解散UIActivityViewController。当您直接关闭它时,您会注意到消除动画未正确显示。 - jrwagz

5

我看到这个问题已经很久了,但我们一直在调试同样的视图控制器不关闭的问题,我希望我的答案能提供一些额外的细节和比手动调用-dismissPopoverAnimated:更好的解决方案。

UIActivity的文档非常稀少,虽然它暗示了实现应该如何结构化,但问题表明它并不像它本应该那么明显。

你应该注意到的第一件事是文档声明你不应该以任何方式手动关闭视图控制器。这实际上是正确的。

文档没有说的是,当你遇到调试无法关闭的视图控制器问题时,iOS将调用你的-activityViewController方法来获取对主题视图控制器的引用。事实证明,可能只有在iPad上,iOS实际上并没有将返回的视图控制器实例存储在其结构中,然后,在它想要关闭视图控制器时,仅仅会向你的-activityViewController请求对象,然后关闭它。在第一次调用该方法(显示时)实例化的视图控制器因此永远不会被关闭。疼。这就是问题的原因。

我们如何正确修复这个问题呢?

进一步浏览UIActivity文档,你可能会偶然发现-prepareWithActivityItems:方法。特别的提示在以下文字中:

如果你的服务实现需要向用户显示其他UI,你可以使用这个方法准备你的视图控制器对象,并使其从activityViewController方法可用。

因此,想法是在-prepareWithActivityItems:方法中实例化你的视图控制器并将其处理为一个实例变量。然后只需从你的-activityViewController方法返回相同的实例即可。

这样一来,在不需要任何手动干预的情况下,调用-activityDidFinish:方法后,视图控制器将被正确地隐藏。

太好了。

NB!进一步挖掘,-prepareWithActivityItems:不应该每次调用时都实例化一个新的视图控制器。如果你之前已经创建了一个,你应该只是重新使用它。在我们的情况下,如果我们没有这样做,它会快乐地崩溃。

希望这能帮助到某些人。:)


完美的解释!感谢您花时间真正找到了根本原因。 - jrwagz

2

我也遇到了同样的问题。我的解决方法是将activityViewController保存为成员变量并返回存储的控制器。Activity会返回新对象,而dismiss操作则在新对象上执行。

    - (UIViewController *)activityViewController {
        if (!self.detaisController) {
            // create detailsController
        }
        return self.detailsController;
    }

1
一个解决方法是要求调用视图控制器通过- (void)performActivity执行到你的目标视图控制器,尽管苹果不建议这样做。
例如:
- (void)performActivity
{

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        [self.delegate performSomething]; // (delegate is the calling VC)
        [self activityDidFinish: YES];
    }
}

- (UIViewController *)activityViewController
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        UIViewController* vc=XXX;

        return vc;
    }
    else
    {
        return nil;
    }
}

1
我将UIActivity传递到另一个视图,然后调用以下内容...
[myActivity activityDidFinish:YES];

这在我的设备和模拟器上都可以运行。请确保您没有覆盖 UIActivity .m 文件中的 activityDidFinish 方法,就像我之前所做的那样。您可以在这里看到我正在使用的代码。


谢谢您的回答,但不,我没有覆盖activityDidFinish:。正如我在问题中所说,相同的代码在iPhone(模拟器和设备)上运行良好,但在iPad(模拟器和设备)上却无法正常工作。 - Stephen Darlington
刚刚在我们的项目中仔细检查了一下,iPhone和iPad模拟器都能正常工作。 - AndyDev
我并不认为示例代码是正确的 - 它关闭了视图控制器,尽管苹果的文档说不要这样做 - 而且它似乎也没有按照我的预期工作...当活动被关闭后,菜单并没有消失。话虽如此,我打算扩展问题以解释我认为应该发生的事情;也许我理解有误。 - Stephen Darlington
删除那行代码也可以,我的项目也支持iOS5,所以我需要找到一种确保只在需要时调用它的方法。重新阅读您的问题,这正是它应该工作的方式,并且Facebook和Twitter也是如此。您在GitHub上有您的项目吗?我很乐意为您查看,因为我们正在试图在uiactivities.com上建立一个活动集合。 - AndyDev
我现在正在查看这个。正如您所指出的,它应该在iPad上显示为弹出窗口,但我目前还没有这样做。我现在要尝试实现这个功能,看看是否会遇到同样的问题,并告诉您我的进展情况。 - AndyDev
显示剩余2条评论

0
所以我遇到了同样的问题,我有一个自定义的UIActivity和一个自定义的activityViewController,当它以模态方式呈现时,无论我尝试什么都无法解除。为了让用户体验保持不变,我选择采用以下解决方法:仍然使用自定义的UIActivity,但给该活动分配一个委托。因此,在我的UIActiviy子类中,我有以下内容:
- (void)performActivity
{
    if ([self.delegate respondsToSelector:@selector(showViewController)]) {
        [self.delegate showViewController];    
    }

    [self activityDidFinish:YES];
}

- (UIViewController *)activityViewController
{
    return nil;
}

然后我将显示UIActivityViewController的视图控制器设置为代理,并在代理方法中显示您通常会在activityViewController中显示的视图控制器。


0

你使用storyboards吗?也许在你的iPad storyboard中,UIActivityIndicatorView没有勾选“停止时隐藏”?

希望能有所帮助!


好的想法,但不行。没有Storyboards或XIBs。WSLInProgressViewController是从UIViewController派生而来,而不是UIActivityIndicatorView(我猜这就是你所说的UIActivityView?)。 - Stephen Darlington
啊,好吧,太糟糕了:( 确实,抱歉,我是指 UIActivityIndicatorView - Thermometer

-1

最后发布怎么样?使用非ARC项目!

[progressView release];

许多用户都有与您相同的问题!另一个解决方案是:

UIActivityIndicatorView *progress= [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125, 50, 30, 30)];
progress.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[alert addSubview:progress];
[progress startAnimating];

如果您正在使用Storyboard,请确保在单击activityind时,"Hides When Stopped"已被选中!

希望这有所帮助...


感谢您的回答,但是... progressView 是自动释放的,因此添加新的释放会导致其被过度释放。 WSLInProgressViewController 不仅仅是一个花哨的 UIActivityIndicatorView,因此它没有 startAnimating 方法。 - Stephen Darlington

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接