无法将数据对象传递给视图控制器内的视图控制器

Posted

技术标签:

【中文标题】无法将数据对象传递给视图控制器内的视图控制器【英文标题】:Can't pass a data object to view controller inside a view controller 【发布时间】:2011-06-14 21:43:18 【问题描述】:

我不知道为什么,但是当视图控制器在另一个视图控制器中被实例化时,我无法将数据对象 (NSManagedObject) 传递给视图控制器。当我在传递对象之前记录对象时,它拥有所有数据,但在它到达视图控制器之后,它是空的。看起来这应该是相当直截了当的,但由于某种原因,它只是没有到达那里。

在实现文件中将 NSManagedObject 分配给接受视图控制器的代码是:viewController.thisCard = aCard;

非常感谢任何帮助。提前致谢。

这是滚动的视图控制器的标题:

@interface HandViewController : UIViewController 
<UIScrollViewDelegate>

    IBOutlet UIScrollView *scrollView;
    IBOutlet UIPageControl *pageControl;

    BOOL pageControlIsChangingPage;
    NSManagedObjectContext *context;


@property (nonatomic, retain) UIView *scrollView;
@property (nonatomic, retain) UIPageControl *pageControl;
@property (nonatomic, retain) NSManagedObjectContext *context;

/* for pageControl */
- (IBAction)changePage:(id)sender;

@end

这是该对象实现中的 viewDidLoad

- (void)viewDidLoad

    scrollView.delegate = self;

    [self.scrollView setBackgroundColor:[UIColor blackColor]];
    [scrollView setCanCancelContentTouches:NO];

    scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    scrollView.clipsToBounds = YES;
    scrollView.scrollEnabled = YES;
    scrollView.pagingEnabled = YES;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Game" inManagedObjectContext:[self context]];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *fetchedGames = [self.context executeFetchRequest:fetchRequest error:&error];

    [fetchRequest release];

    Game *aGame = [fetchedGames objectAtIndex:0];

    CGFloat cx = 0;

    for (Card *aCard in aGame.turnUpcoming.hand) 

        CardViewController *viewController = [[CardViewController alloc] initWithNibName:@"CardViewController" bundle:nil];

        CGRect rect = self.view.frame;
        rect.size.height = scrollView.frame.size.height - 50;
        rect.size.width = scrollView.frame.size.width - 50;
        rect.origin.x = ((scrollView.frame.size.width - rect.size.width) / 2) + cx;
        rect.origin.y = ((scrollView.frame.size.height - rect.size.height) / 2);
        viewController.view.frame = rect;
        viewController.thisCard = aCard;
        [scrollView addSubview:viewController.view];

        cx += scrollView.frame.size.width;

        [viewController release];
    

    self.pageControl.numberOfPages = [aGame.turnUpcoming.hand count];
    [scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

更新:根据请求,我正在从视图控制器添加一些代码

这是 CardViewController 的标题

@interface CardViewController : UIViewController 
    UILabel IBOutlet *cardValue;
    UILabel IBOutlet *cardInstruction;
    UILabel IBOutlet *cardHint;
    UILabel IBOutlet *cardTimer;
    UIButton IBOutlet *playCardButton;

    Card *thisCard;


@property (nonatomic, retain) UILabel IBOutlet *cardValue;
@property (nonatomic, retain) UILabel IBOutlet *cardInstruction;
@property (nonatomic, retain) UILabel IBOutlet *cardHint;
@property (nonatomic, retain) UILabel IBOutlet *cardTimer;
@property (nonatomic, retain) UIButton IBOutlet *playCardButton;
@property (nonatomic, retain) Card *thisCard;

@end

这里是 CardViewController 实现的 viewDidLoad

- (void)viewDidLoad

    [super viewDidLoad];

     if ([thisCard isObjectValid]) 
        cardValue.text = [thisCard.value stringValue];
     


更新:viewDidLoad 中卡片循环的新代码和新 CardView 代码,根据以下建议

viewDidLoad 中的循环:

for (Card *aCard in aGame.turnUpcoming.hand) 

        CGRect rect = scrollView.frame;
        rect.size.height = scrollView.frame.size.height - 50;
        rect.size.width = scrollView.frame.size.width - 50;
        rect.origin.x = ((scrollView.frame.size.width - rect.size.width) / 2) + cx;
        rect.origin.y = ((scrollView.frame.size.height - rect.size.height) / 2);

        tempCardView = [[CardView alloc] initWithFrame:rect];
        tempCardView.thisCard = aCard;

        NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CardView" owner:self options:nil];

        tempCardView = [nibObjects objectAtIndex:0];

        [scrollView addSubview:tempCardView];

        cx += scrollView.frame.size.width;

        [tempCardView release];
    

头文件 CardView.h

@interface CardView : UIView 
    UILabel IBOutlet *cardValue;
    UILabel IBOutlet *cardInstruction;
    UILabel IBOutlet *cardHint;
    UILabel IBOutlet *cardTimer;
    UIButton IBOutlet *playCardButton;

    Card *thisCard;


@property (nonatomic, retain) UILabel IBOutlet *cardValue;
@property (nonatomic, retain) UILabel IBOutlet *cardInstruction;
@property (nonatomic, retain) UILabel IBOutlet *cardHint;
@property (nonatomic, retain) UILabel IBOutlet *cardTimer;
@property (nonatomic, retain) UIButton IBOutlet *playCardButton;
@property (nonatomic, retain) Card *thisCard;

@end

实现文件 CardView.m

@implementation CardView

@synthesize cardHint;
@synthesize cardTimer;
@synthesize cardValue;
@synthesize cardInstruction;
@synthesize playCardButton;
@synthesize thisCard;

- (id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        if ([thisCard isObjectValid]) 
            cardValue.text = [thisCard.value stringValue];
            cardInstruction.text = thisCard.instruction;
            cardHint.text = thisCard.hint;
            cardTimer.text = [thisCard.time stringValue];
        
    
    return self;


@end

更新:6/16 - 添加了 XIB 屏幕截图

CardView.xib

【问题讨论】:

【参考方案1】:

看起来你的 CardViewController 实际上应该是一个 UIView。正如 Apple 所说:“单个视图控制器通常管理与单个屏幕的内容相关的视图,尽管在 iPad 应用程序中可能并非总是如此。”

(更改 UIView 后)在您的循环中,您正在创建一个 tempCard,然后加载另一个。如果您在 IB 中链接了 tempCardView(见下文),那么您只需要:

for (Card *aCard in aGame.turnUpcoming.hand) 
    CGRect rect;
    rect.size.width = scrollView.frame.size.width - 50;
    rect.size.height = scrollView.frame.size.height - 50;
    rect.origin.x = ((scrollView.frame.size.width - rect.size.width) / 2) + cx;
    rect.origin.y = ((scrollView.frame.size.height - rect.size.height) / 2);
    [[NSBundle mainBundle] loadNibNamed:@"CardView" owner:self options:nil];  //magically connected to tempCardView.
    self.tempCardView.frame = rect;
    self.tempCardView.thisCard = aCard;

    [scrollView addSubview:tempCardView];
    cx += scrollView.frame.size.width;
    self.tempCardView = nil;

因此,您有两个 XIB,主要的 XIB 与您的 viewController 一起加载,另一个 (CardView) 为每张卡加载一次。

现在,在 CardView 中,您正试图过早地设置标签。在 initWithFrame(在上述情况下由 loadFromNib 调用)期间,您还没有访问 thisCard 的权限。您将需要 thisCard 的 setter,只要将值分配给 thisCard 属性,就会调用该 setter:

   -(void) setThisCard: (Card *) newCard 
       if (thisCard == newCard) return;
       [newCard retain];
       [thisCard release];
       thisCard = newCard;
       self.cardValue.text = [thisCard.value stringValue];
       self.cardInstruction.text = thisCard.instruction;
       self.cardHint.text = thisCard.hint;
       self.cardTimer.text = [thisCard.time stringValue];
    

现在在界面生成器中,

    使用单个 UIView 创建 CardView.xib,但将 FileOwner 设置为您的 VC,而不是 CardView,因为这将由谁来加载它(并且谁拥有 tempCardView 属性)。 将视图的类型设置为 CardView,然后将其挂钩到 FileOwner(又名 HandViewController)的 tempCardView 属性 将所有其他卡片部件放入该 CardView 并将它们连接到该 CardView 的属性。

你应该准备好了。

【讨论】:

感谢您的回复。我将尝试将其更改为 UIView 并看看会发生什么。完成后我会发布结果。 那么,如果我使用 UIView 管理子视图,而不是 UIViewController - 有没有办法做到这一点,我可以使用 nib 文件来控制 UIView 中的多个对象?如果我不必编写子视图中所有对象的布局,这将使生活变得更加简单。再次感谢。 当然,事实上,您可以在 VC 的 nib 文件的视图中拥有视图。但是我假设您在示例中需要可变数量的它们。在这种情况下,您可以使用 loadNibNamed:owner:options: Set owner 为您的 VC 加载一个,但在您的 VC 中定义一个 tempCardView 属性,该属性链接到您在 IB 中创建的视图。现在在 viewDidLoad 中,调用 loadNibNamed 和 tempCardView 将链接到一个新的 CardView。给它一张卡片,将它链接到你的视图,发布你的副本(因为超级视图保留它),然后再做一遍。 对,忘记了。是的,您需要保留您的自定义 UIView,但实际上它只需要 CardView.h 文件,其中只有.m 中的合成器(除非您喜欢 theCard setter 技巧,如果您在其他时间分配新卡)。所以...(1)获取您的 CardView.xib,但将 FileOwner 设置为您的 VC,而不是您的视图(2)添加一个***视图并将其类型设置为 CardView,然后将其挂钩到 FileOwners tempCardView 属性(3)将所有其他部分放入 CardView 并将它们连接到 CardView 的属性。现在,当您加载 Cardview.xib 时,将设置 tempView 并设置其所有部分。 快到了。这在 tempCardView 连接上是正确的,但您没有第 3 部分:连接到子视图的 CardView 插座。在右上角,这些插座需要连接到左侧 CardView 下的每个对象。例如,cardHint 到 Label-Hint。此外,您还有一个额外的视图悬挂在底部。

以上是关于无法将数据对象传递给视图控制器内的视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何将选定的 uitableviewcell 核心数据对象传递给新的视图控制器?

从 UITableView 选择行时将核心数据对象传递给另一个视图控制器

RxSwift:将实际可观察​​对象传递给另一个视图控制器?

OS X Core Data - 将托管对象上下文传递给视图控制器

将选定对象传递给第二个视图控制器并在 uilabel 中显示

将 JSON 对象传递给控制器