【问题标题】:Why is my object not being passed correctly via segue?为什么我的对象没有通过 segue 正确传递?
【发布时间】:2012-09-17 04:22:34
【问题描述】:

假设我有 2 个控制器,BarViewController 和 FooViewController。

FooViewController 有一个名为 imageView 的 UIImageView 的出口:

@property (nonatomic, weak) UIImageView *imageView;

BarViewController 有一个 UIButton 按钮的出口。 BarViewController 有一个从这个按钮到 FooViewController 的 segue,称为 BarToFooSegue(在故事板中完成)。

当我运行以下代码并在 FooViewController.imageView.image 上调用 NSLog 时,结果为 nil,并且我的图像不会显示。为什么会这样?

// code in BarViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    if([segue.identifier isEqualToString:@"BarToFooSegue"]){
        NSURL *photoUrl = @"http://www.randurl.com/someImage"; // assume valid url
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

        [segue.destinationViewController setImageView:imageView];
    }
}

我尝试将 FooViewController.imageView 设置为强而不是弱,但问题仍然存在:

@property (nonatomic, strong) UIImageView *imageView;

运行我的调试器时,我注意到 FooViewController 中的 imageView 在 prepareForSegue: 中正确更新:但随后又被重新更新为一些新分配的 imageView,其中 @property 图像设置为 nil。我不确定控制流的哪一部分导致了这种情况,因为它发生在用汇编语言编写的行中。

我通过向 FooViewController 添加 UIImage 属性使我的代码正常工作:

@property (nonatomic, strong) UIImage *myImage;

并在 BarViewController 中更改 prepareForSegue: 以传递图像而不是 imageView:

// code in BarViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    if([segue.identifier isEqualToString:@"BarToFooSegue"]){
        NSURL *photoUrl = @"http://www.randurl.com/someImage"; // assume valid url
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];

        [segue.destinationViewController setMyImage:image];
}

在FooViewController中修改viewWillAppear:

- (void)viewWillAppear:(BOOL)animated{
    [self.imageView setImage:self.myImage];
}

【问题讨论】:

    标签: iphone objective-c ios xcode ipad


    【解决方案1】:

    在设置图像之前调用[segue.destinationViewController view];,这将导致视图层次结构被加载,然后您的出口将被设置。

    【讨论】:

    • 这真的是一个好的解决方案吗?如果内存不足,可以随时卸载视图控制器的视图,并在必要时重新加载。因此,在viewDidLoad 中设置imageView 似乎是更可靠的解决方案。
    • 我相信谨慎使用是一个务实的解决方案。与任何模式一样,滥用和误用当然是可能的。情况似乎是 imageView 是目的地并不真正关心的一些装饰的容器,因此添加一个属性来临时存储 UIImage,然后在 viewDidLoad 中设置它似乎过于复杂,语义价值不大。视图将加载,因为您正在准备转场 - 稍微提前加载它可以避免编写胶水代码。
    • OP 设计的一个更有趣的问题是,从prepareForSegue 中的URL 加载会阻塞主线程。我不希望目标视图控制器需要从网络加载,但我可以看到一个异步 NSURLConnection 在 prepareForSegue 中启动,图像设置在完成块中。在这种情况下,您需要确保在完成执行时视图已加载,并强制加载视图是执行此操作的一种方法。 @scott 说 iOS6 在 prepareForSegue 之前加载视图 - 我还没有测试过,但它会有意义。
    【解决方案2】:

    prepareForSegue 中还没有定义出口——它们是零。您正在向 nil 发送消息,这非常好,因此不会给您错误,但在这种情况下,它可能会导致意外行为。您可以通过创建一个临时 UIImage 属性来解决它,并在 viewDidLoad 或 viewWillAppear 中将您的图像视图设置为该图像。

    【讨论】:

    • 对不起,你说的是 [segue.destinationViewController setImageView:imageView];什么都不做,因为 segue.destinationViewController 是 nil?
    • 在 FooViewController 中创建一个临时的 UIImage 属性感觉是多余的。肯定有更简洁的解决方案吗?
    • 目标视图控制器不是 nil,但 imageView 是。您可以通过在 prepareForSegue 中记录图像视图来测试它,它将返回 nil。不,不幸的是,这就是它的完成方式。在 iOS 6 中这是固定的,但如果您需要为 iOS 5 构建,则必须这样做。
    【解决方案3】:

    如果您必须直接设置 imageView.image,我同意 @ikuragames 的回答。但通常情况下,我将 ViewController 的视图层次结构保密。

    我认为将 UIImage 属性添加到 Foo 并不难看。我认为它实际上比@ikuragames 正确的解决方案更漂亮。

    【讨论】:

      【解决方案4】:
      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
      
          if([segue.identifier isEqualToString:@"BarToFooSegue"]){
              NSURL *photoUrl = @"http://www.randurl.com/someImage"; 
              UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
      
         
              FooViewController *vc = [segue destinationViewController];
              vc.myImage = image;   
       }
      }
      

      【讨论】:

      • 这与我解决此问题的代码相同。我主要感兴趣的是为什么会出现这个问题,以及是否有更好的方法来解决它
      猜你喜欢
      • 1970-01-01
      • 2011-09-04
      • 2021-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-09
      • 2021-09-16
      • 2015-06-18
      相关资源
      最近更新 更多