如何使用公共目标对象来处理多个视图的操作/出口? [英] How to use a common target object to handle actions/outlets of multiple views?

查看:122
本文介绍了如何使用公共目标对象来处理多个视图的操作/出口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始尝试使用以前使用过代码的IB。我已经为iPad / iPhone Portrait / Landscape创建了笔尖,所以我有四种可能的视图。所有文件所有者都设置为UIViewController,都有一个对象从调色板集添加到我的NSObject子类TargetObject。设置IBActions / IBOutlets没问题,只需按常规方式按住Ctrl键拖动即可在一个笔尖中创建代码,然后右键单击该对象并将操作/出口拖动到其他笔尖中的右侧控件,以便所有连接都存在碎粒。我们的想法是,应用程序代理启动当前设备的相应视图控制器,然后该视图控制器根据方向加载正确的视图。

I'm beginning to try and use IB where previously I used code. I have created nibs for iPad/iPhone Portrait/Landscape so I have four possible views. All have files owner set to UIViewController, all have an object added from the palette set to my NSObject subclass "TargetObject". No problem setting IBActions/IBOutlets, just ctrl-drag as usual to create the code in one nib, then go and right-click the object and drag the actions/outlets to the right controls in the other nibs so that the connection exists in all nibs. The idea is that the app delegate kicks off the appropriate view controller for the current device and then that view controller loads the right view depending on orientation.

(可能具有自动调整功能这种方法不是必需的 - 我想知道是否可以这样做,因为让布局重新排列自己恰好使用那些IB控件是非常非常令人沮丧的。)

(Maybe with autoresizing mastery this approach is not necessary - I want to know if it is possible to do it this way because getting the layouts to rearrange themselves just right just with those IB controls is very, very frustrating.)

这些一对多视图和目标对象背后的想法是我可以在应用程序的任何地方使用它们。例如,我显示的内容是核心数据
中的对象,我想允许在应用程序的多个位置进行详细查看/编辑。这似乎是一种非常MVC的做事方式。

The idea behind these one-to-many views and target objects is that I can use them anywhere in the app. For example, where I have something displayed which is an object in core data and I would like to allow detail view/edit in multiple places in the app. It seems like a very MVC way to do things.

当我这样做时,问题出现在视图控制器的loadView中:

The problem comes in loadView of the view controller when I do:

NSArray *portraitViewArray = [[NSBundle mainBundle] loadNibNamed:@"Weekview_iPad_Portrait" owner:self options:nil];
portraitWeekView = [portraitViewArray objectAtIndex:0];

NSArray *landscapeViewArray = [[NSBundle mainBundle] loadNibNamed:@"Weekview_iPad_Landscape" owner:self options:nil];
landscapeWeekView = [landscapeViewArray objectAtIndex:0];

// this object is intended to be a common target for portrait and landscape arrays. 
weekViewTarget = [portraitViewArray objectAtIndex:1];

UIInterfaceOrientation interfaceOrientation = self.interfaceOrientation;

if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
    self.view = portraitWeekView;
else 
    self.view = landscapeWeekView;

正如您猜测的那样,纵向方向的一切都很好,但在横向方面,任何与目标对象的交互都会崩溃。 weekViewTarget对象引用使用纵向视图创建的对象,因此横向视图正在查找未使用引用保留的其他实例。在横向视图中_viewDelegate是nil - 它是私有的,所以我无法在代码中修复它。

As you guessed, everything is fine in portrait orientation but in landscape any interaction with the target object crashes. The weekViewTarget object refers to an object created with the portrait view, so the landscape view is looking for a different instance that hasn't been held with a reference. In the landscape view _viewDelegate is nil - it is private so I can't fix it up in code.

我也可以通过引用保持横向目标对象,但是当方向发生变化时会出现问题 - 如果有任何有状态控件,比如UITableView数据源/委托将改变导致轮换的奇怪用户体验。除非我确保目标对象只实现简单的操作,并使用单独的共享对象为任何表视图或所需的文本视图实现数据源/委托对象。

I can hold onto the landscape target object with a reference too, but then there will be problems whenever the orientation changes - in case of any stateful controls like UITableView the datasource/delegate will change resulting in strange user experience on rotation. Unless I ensure the target object implements only simple actions and uses a separate, shared object to implement datasource/delegate objects for any table views or text views required.

我有一件事我们想到的是让目标成为单身人士。看起来像黑客,这将是无法工作的时间。

One thing I have thought of is to make the target a singleton. Seems like a hack and here will be times that can't work.

创建多个视图的正确方法是使用公共目标对象来实现的模型?

What's the right way to create multiple views implemented as nibs using a common target object to do stuff to the model?


  • 进展 - 如果我给每个目标一个指向其自己类型的指针,事情就会开始起作用:

  • progress - things begin to work if I give each target a pointer to its own type:

WeekViewTarget *forwardTarget;


并让实际处理程序的 forwardTarget = nil 而未使用的处理程序的forwardTarget设置如下:

and let the real handler's forwardTarget = nil while the unused handler's forwardTarget is set as follows:

weekViewTarget = [portraitViewArray objectAtIndex:1];
forwardedWeekViewTarget = [landscapeViewArray objectAtIndex:1];
forwardedWeekViewTarget.forwardTarget = weekViewTarget;

然后在每个IBAction中执行以下操作:

and then do the following in each IBAction:

- (IBAction)timeBlockTapped:(id)sender {

    if(forwardTarget != nil) {
        [forwardTarget performSelector:@selector(timeBlockTapped:) withObject:sender];
    } else {
        NSLog(@"Got a tap event with sender %@", [sender description]);
    }
}

尽管感觉还是不对。

推荐答案

亚当,听起来你想要一个代理(又称外部)对象。

Adam, it sounds like you want a proxy (aka external) object.

NSBundle和UINib在从NIB实例化对象图时返回自动释放的数组。在事件循环结束时释放数组时,将释放您未专门保留的任何对象。显然,只要保留其所有者,nib中相互引用的对象就会被保留。

NSBundle and UINib return auto-released arrays when instantiating object graphs from NIBs. Any object you don't specifically retain will be released when the array is released at the end of the event loop. Obviously objects inside the nib that reference each other will be retained as long as their owner is retained.

所以你的第二个动作目标对象实例正在被释放,因为你'不要挂在它上面。

So you 2nd instance of your action target object is being released because you're not hanging on to it.

你真正想要的只是两个NIB都可以引用的目标对象的单个实例。因此,您无法让NIB实例化该对象的实例。但是你的NIB需要能够引用该对象实例!

What you really want is just a single instance of your target object that both NIBs can reference. So you can't have your NIB instantiate an instance of that object. But your NIB needs to be able to make reference to that object instance!

哦亲爱的,该怎么办?!

Oh dear, what to do?!

基本上,外部对象是您放置在NIB中的代理。然后,您在实例化实例化NIB的对象图时输入。 NIB加载程序用您外部提供的实例替换NIB中的代理,并在Interface Builder中配置您分配给代理的任何目标或出口。

Basically an external object is a proxy you place in a NIB. You then feed in the actual instance that when you instantiate the NIB's object graph. The NIB loader replaces the proxy in the NIB with your externally provided instance and configures any targets or outlets you've assigned to the proxy in Interface Builder.


  1. 在Interface Builder中拖动外部对象而不是NSObject实例。它将与Xcode 4.x中的文件所有者一起显示在上部。

  2. 选择它并在Identity Inspector中将其类设置为适当的类型。

  3. 在属性检查器中,将标识符字符串设置为TargetObject(或者您要在下面的代码中使用的任何字符串)。

  4. 利润!

  1. In Interface Builder drag in an "External Object" rather than NSObject instance. It will appear in the upper section along with File's Owner in Xcode 4.x.
  2. Select it and in the "Identity Inspector" set it's class to the appropriate type.
  3. In the "Attributes Inspector" set the Identifier string to "TargetObject" (or whatever string you want to use in the code below).
  4. Profit!



代码



The Code

id owner = self; // or whatever
id targetObject = self.targetObject; // or whatever...

// Construct a dictionary of objects with strings identifying them.  
// These strings should match the Identifiers you specified in IB's 
// Attribute Inspector.
NSDictionary *externalObjects = [NSDictionary dictionaryWithObjectsAndKeys:
                                    targetObject, @"TargetObject",
                                    nil];

// Load the NIBs ready for instantiation.
UINib *portraitViewNib = [UINib nibWithNibName:@"Weekview_iPad_Portrait" bundle:nil];
UINib *landscapeViewNib = [UINib nibWithNibName:@"Weekview_iPad_Landscape" bundle:nil];

// Set up the NIB options pointing to your external objects dictionary.
NSDictionary *nibOptions = [NSDictionary dictionaryWithObjectsAndKeys:
                               externalObjects, UINibExternalObjects, 
                               nil];

// Instantiate the objects in the nib passing in the owner 
// (coincidentally also a proxy in the NIB) and your options dictionary.
NSArray *portraitViewArray =  [portraitViewNib instantiateWithOwner:owner
                                                            options:nibOptions];
NSArray *landscapeViewArray = [landscapeViewNib instantiateWithOwner:owner
                                                             options:nibOptions];

self.view = [(UIInterfaceOrientationIsPortrait(interfaceOrientation)) ? portraitViewArray : landscapeViewArray) objectAtIndex:0];



注释



您正在使用NSBundle加载NIB。你应该使用UINib。读取NIB文件要快得多。此外,它将NIB加载与对象实例化分开。这意味着您可以在init,awakeFromNib或viewDidLoad中加载NIB,而不是实例化NIB的内容。然后在你需要NIB中的实际对象的最后一刻,你可以调用instantiateWithOwner。

Notes

You're using NSBundle to load NIBs. You should be using UINib. It is much faster at reading the NIB files. Also, it separates the NIB loading from the object instantiation. Which means you can load the NIB in your init, awakeFromNib, or viewDidLoad and not instantiate the contents of the NIB. Then at the last possible moment when you need the actual objects in the NIB to you can call instantiateWithOwner.

假设在使用UITableViewController的情况下你会加载你的表格单元格viewDidLoad中的nib,但实际上并没有实例化它们,直到在-tableView中需要该类型的单元格:cellForRowAtIndexPath:。

Say in the case of using a UITableViewController you would load your table cell nibs in viewDidLoad but not actually instantiate them until you needed a cell of that type in -tableView:cellForRowAtIndexPath:.

这篇关于如何使用公共目标对象来处理多个视图的操作/出口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆