我一直在研究Apple在他们的iPhoneCoreDataRecipes应用程序中提供的示例代码,他们正在做的一些我不理解的事情,而且我无法找到资源帮助我。
具体来说,有问题的代码块是:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger section = indexPath.section;
UIViewController *nextViewController = nil; //Why this as opposed to alloc and init?
/*
What to do on selection depends on what section the row is in.
For Type, Instructions, and Ingredients, create and push a new view controller of the type appropriate for the next screen.
*/
switch (section) {
case TYPE_SECTION:
nextViewController = [[TypeSelectionViewController alloc] initWithStyle:UITableViewStyleGrouped];
((TypeSelectionViewController *)nextViewController).recipe = recipe;
break; //Why this as opposed to nextViewController.recipe = recipe???
case INSTRUCTIONS_SECTION:
nextViewController = [[InstructionsViewController alloc] initWithNibName:@"InstructionsView" bundle:nil];
((InstructionsViewController *)nextViewController).recipe = recipe;
break;
case INGREDIENTS_SECTION:
nextViewController = [[IngredientDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
((IngredientDetailViewController *)nextViewController).recipe = recipe;
if (indexPath.row < [recipe.ingredients count]) {
Ingredient *ingredient = [ingredients objectAtIndex:indexPath.row];
((IngredientDetailViewController *)nextViewController).ingredient = ingredient;
}
break;
default:
break;
}
// If we got a new view controller, push it .
if (nextViewController) {
[self.navigationController pushViewController:nextViewController animated:YES];
[nextViewController release];
}
}
我想知道((名称*)名称).thing = aThing是否与name.thing = aThing不同?我确定它是,但我找不到任何文件来帮助我理解他们在这里做了什么以及为什么?
另外,为什么他们将nextViewController设置为nil而不是仅仅分配和初始化它?有没有理由在这里完成,而在其他领域创建临时视图控制器时,他们使用alloc和init?
提前感谢您的帮助!
答案 0 :(得分:2)
我将按照他们在代码中出现的顺序而不是您提出的顺序来回答您的问题,因为此处的顺序非常重要。
我们在第一次声明变量时不创建视图控制器的原因是因为我们还不知道我们想要创建什么。想一想:你想写alloc] init]
。但是alloc
之前发生了什么?我们还不知道。我们知道它是UIViewController的一些子类,但我们不知道实际的类。这就是代码的下一部分。
现在我们了解该方法的主要逻辑。我们正在分配视图控制器的配方,但这里有一个问题:我们将变量声明为UIViewController*
,而UIViewController没有recipe
属性。我们知道我们的子类确实如此,但我们已经告诉编译器这个变量指向UIViewController。因此,为了让编译器让我们执行此属性赋值,我们需要将变量强制转换为正确的类。
顺便说一句,我们也可以将变量声明为id nextViewController
,然后编写[nextViewController setRecipe:recipe]
并且不需要强制转换。缺点是编译器无法对我们的代码进行类型检查 - 我们可能会在代码的一些很少使用的分支中意外地将NSString分配给nextViewController
,直到我们碰巧碰到那个我们才知道在运行时分支。
答案 1 :(得分:1)
这是由于推断的类型以及编译器如何处理点语法。
编译器认为nextViewController
是UIViewController
,因为它是如何声明的。您可以将它设置为您想要的任何内容(尽管它应该只设置为UIViewController
个实例,UIViewController
子类实例或nil
),但编译器会将其视为{{ 1}}。当您使用Obj-C 2.0点语法时:
UIViewController
编译器检查myObject.recipe = recipe;
的类型,并查看它是否声明了myObject
方法。如果是,则该语句被转换为等效于:
setRecipe:
然后编译。如果没有[myObject setRecipe:recipe];
的声明,它将尝试将点语法视为结构元素,这几乎肯定会引发编译器警告。类型转换setRecipe:
告诉编译器将变量视为该类型的某个类型,所以当你这样做时:
(TypeSelectionViewController *)
编译器查看是否在((TypeSelectionViewController *)nextViewController).recipe = recipe;
类上声明了setRecipe:
方法,而不是声明为TypeSelectionViewController
的任何方法。
答案 2 :(得分:0)
((TypeSelectionViewController *)nextViewController).recipe
nextViewController是一个UIViewController *,它没有配方属性。 ((TypeSelectionViewController *)nextViewController)
将nextViewController转换为TypeSelectionViewController *。
nextViewController在开关块外部设置为nil,以便准备好在开关内的每个块。注意在每个case块中,alloc和init是如何在不同的类型上:TypeSelectionViewController vs InstructionsViewController等。