【问题标题】: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

【问题讨论】:

    标签: iphone objective-c ios cocoa-touch


    【解决方案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];
        }
    

    现在在界面生成器中,

    1. 使用单个 UIView 创建 CardView.xib,但将 FileOwner 设置为您的 VC,而不是 CardView,因为这将由谁来加载它(并且谁拥有 tempCardView 属性)。
    2. 将视图的类型设置为 CardView,然后将其挂钩到 FileOwner(又名 HandViewController)的 tempCardView 属性
    3. 将所有其他卡片部件放入该 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。此外,您还有一个额外的视图悬挂在底部。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    相关资源
    最近更新 更多