Objective-C 中的一种奇怪类型转换

3
我发现一个演示代码片段,其中使用了类型转换,如下所示:(int)view。'view'是UIView对象的指针。我从来没有知道它可以用于类型转换。有人可以帮我解释一下吗? 粘贴代码在此处
- (CGPoint)accelerationForView:(UIView *)view
{
    // return
    CGPoint accelecration;

    // get acceleration
    NSValue *pointValue = [self._accelerationsOfSubViews objectForKey:
                                     [NSNumber numberWithInteger:(int)view]];
    if (pointValue == nil) {
        accelecration = CGPointZero;
    }
    else {
        [pointValue getValue:&accelecration];
    }

    return accelecration;
}

- (void)willRemoveSubview:(UIView *)subview
{
    [self._accelerationsOfSubViews removeObjectForKey:
                         [NSNumber numberWithInt:(int)subview]];
}

这些演示片段在哪里? - borrrden
1
你必须发布代码。 - Pochi
你需要在这里展示实际的代码片段以供检查。表面上看,没有什么好的理由(甚至没有太多坏的理由)去这样做。 - Ben Zotto
1
@BenZotto:sizeof(int)不能保证等于sizeof(id),所以有这个问题。事实上,在64位的Mac上,它明确地不相等。 - Jonathan Grynspan
@HotLicks:更安全的方法是[NSNumber numberWithUnsignedLongLong:(uintptr_t)theObject]; 更好的方法是使用视图作为目标对象的objc_get/setAssociatedObject() - Jonathan Grynspan
显示剩余9条评论
2个回答

5
[NSNumber numberWithInteger:(int)view]

view不是类型为UIView的对象,而是类型为UIView*的指针。上面的代码将指针转换为整型以存储在NSNumber中,显然是为了将其用作字典中的键。由于指针本身不是对象,所以无法将它们用作字典键。但是,如果你从指针创建一个NSNumber实例,则可以使用生成的对象作为键。有时人们会这样做,以跟踪一些信息,这些信息希望与一些对象(如视图)相关联,但这些信息本身没有存储在对象中(如加速度)。

正如我在下面的评论中提到的那样,这里的代码使用了+numberWithInteger:,这很好,因为该方法接受NSInteger,在32位系统上是32位,在64位系统上是64位。然而,作者随后通过转换为int来使这个好决定失效了,即使在64位系统上通常也是32位。强制转换应该真正是NSInteger,像这样:

[NSNumber numberWithInteger:(NSInteger)view]

1
如果您想使用弱键映射到对象,请查看NSHashMap。 - nielsbot
1
另外,如果您想封装一个对象指针,请使用 +[NSValue valueWithPointer:] - nielsbot
@nielsbot 我相信你指的是NSHashTable,你是对的--那肯定是更好的选择。但这段代码可能是在iOS 6之前编写的。 - Caleb
实际上,我想要的是 NSMapTableNSHashTable 类似于 NSArray,但它支持弱引用值。NSMapTable 类似于带有弱引用键和/或值的 NSDictionary - nielsbot
1
@nielsbot 这就是为什么人们喜欢Lisp。只有一种数据结构,你永远不会选错。;-) - Caleb
显示剩余3条评论

1
(注意:这是在 @Caleb 的答案基础上构建的,假设原始代码试图将 acceleration 值与 UIView 关联起来)
我会通过类别为 UIView 添加一个加速度属性,就像这样:

UIView+acceleration.h:

@interface UIView ( Acceleration )
@property ( nonatomic ) CGPoint acceleration ;
@end

UIView+acceleration.m

#import <objc/runtime.h>

@implementation UIView ( Acceleration )

const char * kAccelerationKey = "acceleration" ; // should use something with a prefix just in case

-(void)setAcceleration:(CGPoint)acceleration
{
    objc_setAssociatedObject( self, kAccelerationKey, [ NSValue valueWithCGPoint:acceleration ], OBJC_ASSOCIATION_RETAIN_NONATOMIC ) ;
}

-(CGPoint)acceleration
{
    return [ objc_setAssociatedObject( self, kAccelerationKey ) CGPointValue ] ;
}

@end

删除 -accelerationForView:-willRemoveSubview:,使用 view.acceleration = <some point><some point> = view.acceleration。这与 IT 相关。

根据代码编写的时间,原始作者可能没有这个选项。而且,将其添加到 UIView 中的一个缺点是,你的应用程序中的每个视图都会有一个加速度,这可能过于冗余。一个更好的方法可能是创建一个 UIView 的子类来跟踪加速度。然后,你可以将其他任何视图放在这个容器中。 - Caleb
我更喜欢组合而非子类化。这里的重点是要显式地将“加速度”添加到系统中的所有UIView,以便您不必用子类替换所有UIView。(它只是普通的UIView。)资源消耗几乎为零,与OP当前代码大致相等。2个方法(每个进程存在一次),除了那些已设置“加速度”的视图之外,没有任何存储。 - nielsbot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接