Каков правильный шаблон для создания экземпляра контроллера представления конкретного устройства в универсальном приложении? - PullRequest
0 голосов
/ 12 апреля 2011

Я новичок в объективе-C, так что терпите меня.Я начал с шаблона универсального приложения в Xcode4 и создал свое приложение.Существует соглашение, что шаблон начинает вас с того, что я пытался придерживаться.Для каждого View Controller есть основной файл и подкласс для каждого типа устройства.Например:

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версия View Controller.Это необходимо, потому что контроллеры вида iPad и iPhone подключены к отдельным, указанным устройствам.

Каков «правильный» шаблон для этого?


ОБНОВЛЕНИЕ

Я нашел этот ответ о загрузке отдельных XIB-файлов с использованием модификаторов устройства, что может помочь в случае, когда мне не нужен определенный подкласс для одного устройства,но это все равно не поможет, если мне понадобится создать экземпляр _iPhone или _iPad экземпляра контроллера представления для определенных функций устройства.

1 Ответ

1 голос
/ 12 апреля 2011

Есть два простых способа решить вашу проблему. Оба будут работать, когда помещены в ваш суперкласс.

Первый метод работает только потому, что у вас есть два разных класса, и какой из них создается, зависит от используемого устройства. Это не не работает, если вы не используете разные классы, потому что нет кода для конкретного устройства. Это включает в себя запрос объекта для своего класса, чтобы решить, какой он есть. Поскольку класс объекта будет классом, специфичным для устройства, даже когда суперкласс запрашивает его, вы можете проверить, какой класс был создан, и действовать соответствующим образом.

- (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 добавила свойство в класс UIDevice в iOS 3.2, которое называется «пользовательский интерфейс». В настоящее время возможны два значения: UIUserInterfaceIdiomPad и UIUserInterfaceIdiomPhone. Так как они не существуют в версиях до 3.2, Apple также добавила макрос, который будет возвращать 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];
}
...