在通用应用程序中实例化设备特定视图控制器的正确模式是什么?

发布于 10-31 10:26 字数 2114 浏览 4 评论 0原文

我是 Objective-C 的新手,所以请耐心等待。我从 Xcode4 中的通用应用程序模板开始并构建了我的应用程序。模板有一个我试图坚持的约定。对于每个视图控制器,每种设备类型都有一个主文件和一个子类。例如:

Project/
    ExampleViewController.(h|m)
    - iPhone/
      - ExampleViewController_iPhone.(h|m|xib)
    - iPad/
      - ExampleViewController_iPad.(h|m|xib)

在大多数情况下,这非常方便。大多数逻辑都在超类中,子类负责任何设备特定的实现。

这是我不明白的部分。有时,我的代码在每个子类中执行相同的操作,只是因为我需要为每个设备加载不同的 xib。例如:

ExampleViewController_iPhone

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    ContentDetailViewController_iPhone *detailViewController = [[ContentDetailViewController_iPhone alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

ExampleViewController_iPad

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    ContentDetailViewController_iPad *detailViewController = [[ContentDetailViewController_iPad alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

...请注意,在第二个实例中,唯一不同的是它加载了视图控制器的 _iPad 版本。这是必要的,因为 iPadiPhone 视图控制器附加到单独的、设备特定的笔尖。

这样做的“正确”模式是什么?


更新

我找到了这个答案 关于使用设备修饰符加载单独的 xib,这似乎可以在我不需要一个设备的特定子类的情况下有所帮助,但如果我需要实例化视图控制器的特定 _iPhone_iPad 实例以实现设备特定功能。

I'm new to objective-C so, bear with me. I started with the Universal App template in Xcode4 and built my application. There is a convention that the template starts you off with that I tried to stick with. For each View Controller, there's a main file and a subclass for each device type. For example:

Project/
    ExampleViewController.(h|m)
    - iPhone/
      - ExampleViewController_iPhone.(h|m|xib)
    - iPad/
      - ExampleViewController_iPad.(h|m|xib)

For the most part, this is pretty convenient. Most of the logic goes in the superclass and the subclasses take care of any device specific implementation.

Here's the part I don't get. Sometimes I have code that does the same thing in each subclass simply because I need to load a different xib for each device. For example:

ExampleViewController_iPhone

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    ContentDetailViewController_iPhone *detailViewController = [[ContentDetailViewController_iPhone alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

ExampleViewController_iPad

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    ContentDetailViewController_iPad *detailViewController = [[ContentDetailViewController_iPad alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

... notice that in the second instance the only thing different is that it's loading the _iPad version of the View Controller. This is necessary because the iPad and iPhone view controllers are attached to separate, device specifc nibs.

What's the "correct" pattern for doing this?


UPDATE

I found this answer about loading separate xibs using device modifiers which seems like it could help in the case where I don't need a specific subclass for one device, but it still won't help if I need to instantiate a specific _iPhone or _iPad instance of a view controller for device specific functionality.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

時窥2024-11-07 10:26:31

有两种简单的方法可以解决您的问题。当放入您的超类中时,两者都会起作用。

第一种方法仅有效,因为您有两个不同的类,并且创建哪个类取决于所使用的设备。如果您不使用不同的类,它就不起作用,因为没有特定于设备的代码。它涉及询问对象的类来决定它是哪个类。由于对象的类将是特定于设备的类,因此即使超类要求,您也可以检查创建了哪个类并采取相应的操作。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    Class classToUse;
    if([self class] == [ExampleViewController_iPad class]) {
        // We are running on the iPad
        classToUse = [ContentDetailViewController_iPad class];
    } else {
        // We must be running on either the iPhone or iPod touch
        classToUse = [ContentDetailViewController_iPhone class];
    }
    // Just use superclass for typing here, since we aren't doing anything device specific
    ContentDetailViewController *detailViewController = [[classToUse alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

第二种方法适用于程序中的任何位置。 Apple 在 iOS 3.2 中向 UIDevice 类添加了一个称为“用户界面习惯用法”的属性。目前有两个可能的值:UIUserInterfaceIdiomPadUIUserInterfaceIdiomPhone。由于这些在 3.2 之前的版本中不存在,Apple 还添加了一个宏,如果版本低于 3.2,则返回 UIUserInterfaceIdiomPhone;如果版本大于 3.2,则从 UIDevice 对象获取实际值或等于3.2。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    Class classToUse;
    // If you aren't supporting versions prior to 3.2, you can use [UIDevice currentDevice].userInterfaceIdiom instead to save a couple of cycles
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // We are running on the iPad
        classToUse = [ContentDetailViewController_iPad class];
    } else {
        // We must be running on either the iPhone or iPod touch
        classToUse = [ContentDetailViewController_iPhone class];
    }
    // Just use superclass for typing here, since we aren't doing anything device specific
    ContentDetailViewController *detailViewController = [[classToUse alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

There are two simple ways to solve your problem. Both will work when placed in your superclass.

The first method only works because you have two different classes, and which one is created depends on the device being used. It does not work if you don't use different classes because there is no device-specific code. It involves asking the object for its class to decide which it is. Since the object's class will be the device-specific class, even when asked for by the superclass, you can check to see which class was created and act accordingly.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    Class classToUse;
    if([self class] == [ExampleViewController_iPad class]) {
        // We are running on the iPad
        classToUse = [ContentDetailViewController_iPad class];
    } else {
        // We must be running on either the iPhone or iPod touch
        classToUse = [ContentDetailViewController_iPhone class];
    }
    // Just use superclass for typing here, since we aren't doing anything device specific
    ContentDetailViewController *detailViewController = [[classToUse alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

The second method will work in any location in your program. Apple added a property to the UIDevice class in iOS 3.2 called the "user interface idiom". There are currently two possible values: UIUserInterfaceIdiomPad and UIUserInterfaceIdiomPhone. Since these don't exist in versions prior to 3.2, Apple also added a macro which will return UIUserInterfaceIdiomPhone if the version is less than 3.2, and get the actual value from the UIDevice object if it is greater than or equal to 3.2.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Content *selectedContent = (Content *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    Class classToUse;
    // If you aren't supporting versions prior to 3.2, you can use [UIDevice currentDevice].userInterfaceIdiom instead to save a couple of cycles
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // We are running on the iPad
        classToUse = [ContentDetailViewController_iPad class];
    } else {
        // We must be running on either the iPhone or iPod touch
        classToUse = [ContentDetailViewController_iPhone class];
    }
    // Just use superclass for typing here, since we aren't doing anything device specific
    ContentDetailViewController *detailViewController = [[classToUse alloc] init];
    detailViewController.content = selectedContent;
    detailViewController.managedObjectContext = self.managedObjectContext;

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文