我已经看到使用 '(ClassName *)' 来引用某些对象的代码语句,例如在UITableViewCell *myCell = (UITableViewCell*)[self.view viewWithTag:1];
.
我不知道这意味着什么或它是如何工作的,我想增加我对这个概念的理解。
我还看到在方法声明中也使用了相同的代码,并且想了解这是否使用相同的概念,如果不是,它有什么不同,例如
-(IBAction)myAction:(id)sender;
我已经看到使用 '(ClassName *)' 来引用某些对象的代码语句,例如在UITableViewCell *myCell = (UITableViewCell*)[self.view viewWithTag:1];
.
我不知道这意味着什么或它是如何工作的,我想增加我对这个概念的理解。
我还看到在方法声明中也使用了相同的代码,并且想了解这是否使用相同的概念,如果不是,它有什么不同,例如
-(IBAction)myAction:(id)sender;
这用作类型转换。它将指针的类型转换为括号内的类型。在这种情况下,它将一个UIView
实例(的结果`viewWithTag:
)转换为一个实例UITableViewCell
。
在 ObjC 中,对象到对象的类型转换不会导致类型转换。也就是说 - 没有创建新实例。此外,在执行动态向下转换时,对对象进行类型转换不会执行动态类型检查(与dynamic_cast
C++ 或 Java 中的类型转换不同,可能会引发异常)。
因为-viewWithTag:
返回一个UIView
(或NSView
在 OS X 上),一个类型转换用于告诉编译器“没关系 - 我知道这个返回的类型是一个UITableViewCell
实例”。UIView
使用类型转换允许您在赋值表达式中从其子类向下转换UITableViewCell
为变量,这允许您将对象用作UITableViewCell
编译器将消息或变量与类型匹配。如果没有类型转换,您将在逻辑上将其用作或分配给UIView
(或其超类之一),如果您尝试使用实例的子类实现的方法,编译器会抱怨。例如 - 如果没有类型转换、类型擦除或编译器警告或错误,您将无法成功使用该变量访问 UITableViewCell.accessoryView 属性。在这种情况下,类型转换是最不邪恶的。
现在- (IBAction)myAction:(id)sender;
,id
是一个无类型的 ObjC 对象。它有一个特殊的区别,它不需要类型转换。例如:
- (IBAction)myAction:(id)sender
{
NSString * currentTitle = nil;
currentTitle = sender.currentTitle; // << May be ambiguous to the compiler because `id` is not fully typed
UIButton * button = sender; // << OK assign id to variable of arbitrary ObjC object type
currentTitle = button.currentTitle; // << OK
UIButton * castButton = (UIButton*)sender; // << although unnecessary, some people use this form.
currentTitle = castButton.currentTitle; // << OK
...
NSObject * object = button; // << OK. upcast from button to object. compiler knows it is an NSObject without typecasting.
就个人而言,我只是将它全部包装到参数中——这对于方法声明中的 ObjC 对象来说很好,只要您知道正在传递的参数的类型:
- (IBAction)myAction:(UIButton *)pButton
{
NSString * currentTitle = pButton.currentTitle; // << OK
...
只是抑制编译器警告所必需的类型转换。换句话说,它对编译器 [self.view viewWithTag:1] 的说法是一个 UITableViewCell。如果没有这种转换,编译器会抱怨 UIView 不是 UITableViewCell。