Objective-c中的一种奇怪类型转换
我发现了一个使用如下类型转换的演示片段:(int)视图。“视图”是UIView对象的指针。我从来都不知道它可以用来铸造类型。有人能帮我解释一下吗? 在这里粘贴代码Objective-c中的一种奇怪类型转换,objective-c,ios,casting,uikit,Objective C,Ios,Casting,Uikit,我发现了一个使用如下类型转换的演示片段:(int)视图。“视图”是UIView对象的指针。我从来都不知道它可以用来铸造类型。有人能帮我解释一下吗? 在这里粘贴代码 - (CGPoint)accelerationForView:(UIView *)view { // return CGPoint accelecration; // get acceleration NSValue *pointValue = [self._accelerationsOfSubVie
- (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]];
}
view
不是类型为UIView
的对象,它是类型为UIView*
的指针。上面的代码将指针强制转换为int,目的是将其存储在NSNumber
中,显然是为了将其用作字典中的键。因为指针本身不是对象,所以不能将其用作字典键。但是,如果从指针创建NSNumber
的实例,则可以将生成的对象用作键。人们有时做这类事情是为了跟踪一些他们想与许多对象(如视图)关联的信息,而这些对象本身并没有存储(如加速度)
正如我在下面的评论中提到的,这里的代码使用了+numberWithInteger:
,这很好,因为该方法使用NSInteger
,在32位系统中为32位,在64位系统中为64位。然而,作者随后通过强制转换为int
,取消了这个好决定,即使在64位系统上,它通常也是32位的。演员阵容应该是NSInteger
,如下所示:
[NSNumber numberWithInteger:(NSInteger)view]
(注意:这是基于@Caleb的答案,假设原始代码试图将加速度
值与UIView关联)
我会通过一个类别向UIView添加一个加速属性,如下所示:
[NSNumber numberWithInteger:(NSInteger)view]
UIView+加速度。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
#导入
@实现视图(加速)
const char*kAccelerationKey=“加速度”//应该使用带有前缀的东西以防万一
-(无效)设定加速度:(CGPoint)加速度
{
objc_setAssociatedObject(self,kaAccelerationKey,[NSValue valueWithCGPoint:acceleration],objc_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGPoint)加速度
{
返回[objc_setAssociatedObject(self,kAccelerationKey)CGPointValue];
}
@结束
删除
-accelerationForView:
和-willRemoveSubview:
并使用view.acceleration=
或=view.acceleration
这些演示片段在哪里?您必须发布代码。您需要在此处显示实际片段以供检查。表面上看,这样做没有什么好的理由(甚至没有太多坏的理由)。@BenZotto:sizeof(int)
不能保证等于sizeof(id)
,所以就是这样。事实上,在64位Mac上,它显然不是。它们显然使用视图的地址作为密钥。提供64位地址是不可靠的,但从技术上讲是合法的。这是危险的。看起来原始工程师正试图使用对对象的弱引用作为字典的键。问题是,如果解除分配键对象(视图),最终将导致有效的内存泄漏。如果在内存中的同一点分配了另一个视图,那么您就有了与之关联的数据,而这些数据不应该被分配。更不用说sizeof(id)
并不总是等于sizeof(int)
,这意味着演员可以丢弃重要的部分。@JonathanGrynspan我不知道我是否会称之为危险——视图本身并不会被释放。只要字典跟踪的视图由一个对象(如包含视图或视图控制器)管理,我就不认为这是一件可怕的事情。不过,同意你的第二点——假设一个指针与int
的大小相同是一个糟糕的计划。最初的作者使用+numberwinteger:
的想法是正确的,因为NSInteger
更接近指针的大小,但是强制转换应该是NSInteger
,而不是int
。如果您想使用弱键映射到对象,请同时查看nshashMap,如果要封装对象指针,请使用+[NSValue valueWithPointer:
@nielsbot这就是人们喜欢Lisp的原因。由于只有一个数据结构,因此不会有选择错误数据结构的危险。;-)根据代码的编写时间,原始作者可能没有该选项。此外,将其添加到UIView
中的一个缺点是,应用程序中的每个视图都会有加速,这可能会有些过头。更好的方法可能是创建一个跟踪加速的UIView子类。然后,您可以将其用作任何其他视图的容器。我更喜欢组合而不是子类化。这里的要点是显式地将加速
添加到系统中的所有UIView中,这样就不必用子类替换所有的UIView
s。(它只是普通的老版本UIView
)资源消耗几乎为零,大约等于OP的当前代码。2种方法(每个进程存在一次),除已设置了加速
的视图外,存储为零。