gpt4 book ai didi

iphone - viewDidLoad 实际上是在每次有 segue 转换时调用的

转载 作者:技术小花猫 更新时间:2023-10-29 10:57:29 26 4
gpt4 key购买 nike

我看过很多关于堆栈溢出的帖子,指出 Controller 的 viewDidLoad 方法仅在第一次访问 Controller 时调用,不一定每次都调用,但总是至少调用一次。

这根本不是我看到的!我整理了一个简单的测试来强调这一点:
https://github.com/imuz/ViewDidLoadTest

似乎导航 Controller segues 和模态视图 viewDidLoad 总是被调用。唯一不调用它的是在选项卡之间切换时。

我能找到的对 viewDidLoad 的每一个解释都与此相矛盾:

  • When is viewDidLoad called?
  • UIViewController viewDidLoad vs. viewWillAppear: What is the proper division of labor?
  • http://www.manning-sandbox.com/thread.jspa?threadID=41506

  • 苹果自己的文档表明只有在内存不足时才会卸载 View 。

    我目前正在 viewDidLoad 中进行初始化,并假设每次 segue 转换都会调用它。

    我在这里错过了什么吗?

    最佳答案

    菲利普米尔斯的回答是正确的。这只是对它的增强。

    系统按记录工作。

    您看到 viewDidLoad 因为被推送到导航 Controller 的 View Controller 是 实例。它必须调用 viewDidLoad。

    如果您进一步调查,您会看到这些 View Controller 中的每一个在弹出时都被释放(只需在 dealloc 中放置一个断点或 NSLog)。这个释放与 View Controller 容器无关......它不控制它使用的 Controller 的生命......它只是持有对它的强引用。

    当 Controller 从导航 Controller 堆栈中弹出时,导航 Controller 释放它的引用,并且由于没有其他对它的引用, View Controller 将释放。

    导航 Controller 仅持有对其事件堆栈中的 View Controller 的强引用。

    如果你想复用同一个 Controller ,负责重用它。当您使用 Storyboard转场时,您(在很大程度上)放弃了该控制。

    假设您有一个 push继续查看 Controller Foo作为点击某个按钮的结果。当点击该按钮时,“系统”将创建 Foo 的实例。 (目标 View Controller ),然后执行 segue。 Controller 容器现在拥有对该 View Controller 的唯一强引用。完成后,VC 将解除分配。

    由于它每次都会创建一个新的 Controller ,viewDidLoad每次出现该 Controller 时都会调用。

    现在,如果你想改变这种行为,并缓存 View Controller 以供以后重用,你必须专门这样做。如果您不使用 Storyboard转场,这很容易,因为您实际上是将 VC 推送/弹出到导航 Controller 。

    但是,如果您使用 Storyboard转场,那就有点麻烦了。

    有很多方法可以做到这一点,但都需要某种形式的黑客攻击。 Storyboard本身负责实例化新的 View Controller 。一种方法是覆盖 instantiateViewControllerWithIdentifier .这是当 segue 需要创建 View Controller 时调用的方法。甚至对于您没有为其分配标识符的 Controller 也会调用它(如果您不分配一个,系统会提供一个虚构的唯一标识符)。

    请注意,我希望这主要用于教育目的。我当然不是建议这是解决您的问题的最佳方法,无论它们是什么。

    就像是...

    @interface MyStoryboard : UIStoryboard
    @property BOOL shouldUseCache;
    - (void)evict:(NSString*)identifier;
    - (void)purge;
    @end
    @implementation MyStoryboard
    - (NSMutableDictionary*)cache {
    static char const kCacheKey[1];
    NSMutableDictionary *cache = objc_getAssociatedObject(self, kCacheKey);
    if (nil == cache) {
    cache = [NSMutableDictionary dictionary];
    objc_setAssociatedObject(self, kCacheKey, cache, OBJC_ASSOCIATION_RETAIN);
    }
    return cache;
    }
    - (void)evict:(NSString *)identifier {
    [[self cache] removeObjectForKey:identifier];
    }
    - (void)purge {
    [[self cache] removeAllObjects];
    }
    - (id)instantiateViewControllerWithIdentifier:(NSString *)identifier {
    if (!self.shouldUseCache) {
    return [super instantiateViewControllerWithIdentifier:identifier];
    }
    NSMutableDictionary *cache = [self cache];
    id result = [cache objectForKey:identifier];
    if (result) return result;
    result = [super instantiateViewControllerWithIdentifier:identifier];
    [cache setObject:result forKey:identifier];
    return result;
    }
    @end

    现在,你必须使用这个 Storyboard。不幸的是,虽然 UIApplication 保留了主 Storyboard,但它并没有公开 API 来获取它。然而,每个 View Controller 都有一个方法, storyboard获取创建它的 Storyboard。

    如果您正在加载自己的 Storyboard,那么只需实例化 MyStoryboard。如果您使用的是默认 Storyboard ,则需要强制系统使用您的特殊 Storyboard 。同样,有很多方法可以做到这一点。一种简单的方法是覆盖 View Controller 中的 Storyboard访问器方法。

    您可以使 MyStoryboard 成为将所有内容转发到 UIStoryboard 的代理类,或者您可以对主 Storyboard进行 isa-swizzle,或者您可以让本地 Controller 从其 Storyboard方法中返回一个。

    现在,请记住,这里有一个问题。如果你将同一个 View Controller 多次推送到堆栈上怎么办?使用缓存,完全相同的 View Controller 对象将被多次使用。这真的是你想要的吗?

    如果不是,那么您现在需要管理与 Controller 容器本身的交互,以便它们可以检查该 Controller 是否已为它们所知,在这种情况下,需要一个新实例。

    所以,有 一种在使用默认 Storyboard segues 时获取缓存 Controller 的方法(实际上有很多方法)......但这不一定是一件好事,当然也不是你默认得到的。

    关于iphone - viewDidLoad 实际上是在每次有 segue 转换时调用的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11969452/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com