2013-02-13 105 views
1

我有一个自定义的UIView,它是一个带圆角矩形的阴影和一个小边框。CGContextSetShadowWithColor在设备上没有显示

- (void) drawRect:(CGRect)rect { 
    //// General Declarations 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    //// Shadow Declarations 
    CGColorRef shadow = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.3].CGColor; 
    CGSize shadowOffset = CGSizeMake(0, 1); 
    CGFloat shadowBlurRadius = 2; 

    //// Abstracted Graphic Attributes 
    CGRect roundedRectangleFrame = CGRectMake(2, 0, rect.size.width - 4, rect.size.height - 2); 


    //// Rounded Rectangle Drawing 
    UIBezierPath* roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect: roundedRectangleFrame cornerRadius: 2]; 
    CGContextSaveGState(context); 
    CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow); 
    [[UIColor whiteColor] setFill]; 
    [roundedRectanglePath fill]; 
    CGContextRestoreGState(context); 

    [[UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:0.3] setStroke]; 
    roundedRectanglePath.lineWidth = 0.5; 
    [roundedRectanglePath stroke]; 
} 

我的问题是,在模拟器中一切都完美呈现,但是当我在设备上运行的代码(我用的iPod touch 4代)只呈现圆角矩形和边框,但没有阴影。有任何想法吗?

+0

您是否尝试过更大的阴影? – Larme 2013-02-13 16:18:11

+0

是的,我尝试过,无论我做得有多大,它都会显示在设备上,甚至尝试使用红色。 – FrankWest 2013-02-13 16:22:46

+0

你是否在超越界限?即被剪切的影子? – 2013-02-13 16:26:33

回答

3

你已经找到了解决方案,但我会解释为什么你原来的代码没有工作,为什么你的解决方案工作。

您正在使用ARC,这意味着编译器会自动为您管理Objective-C对象的生命周期。但编译器不知道或管理Core Foundation对象的生命周期。你原来的代码这样说:

CGColorRef shadow = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.3].CGColor; 

当你调用+[UIColor colorWithRed:green:blue:],它返回到UIColor对象的引用。您立即发送CGColor消息到UIColor对象,得到CGColorRef

由于在方法的后面不使用UIColor对象,因此编译器认为在该语句结束时立即释放UIColor对象是安全的。释放UIColor会释放它。当它被释放时,UIColor对象释放CGColor对象。由于您没有声明CGColor对象的所有权,因此该版本取消分配CGColor对象。到达CGContextSetShadowWithColor语句时,包含CGColor对象的内存处于未知状态。

您的解决方案通过将+[UIColor colorWithRed:green:blue:]消息嵌入到使用CGColor对象的语句中来解决该问题。所以当声明结束并且UIColor被释放和释放时,您已经将CGColor关闭到图形上下文,该上下文保留它,防止它被释放。

这也是我解决问题的方法。但还有其他方法。另一种方法是明确声明CGColor对象的所有权:

CGColorRef shadow = CGColorRetain([UIColor colorWithRed:0.0/255.0 
    green:0.0/255.0 blue:0.0/255.0 alpha:0.3].CGColor); 

... 

CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow); 
CGColorRelease(shadow); 
+0

谢谢你的不错的和详细的解释。我不知道ARC不知道如何处理CF对象,尽管我总是怀疑ARC在这个“魔术”下做了什么。 – FrankWest 2013-02-13 21:15:08

1

我不能解释为什么,而不是使用使用UIColor表达式本身的CGColorRef“解决”了问题。现在它可以在模拟器和设备上的所有分辨率下呈现完美效果。

的工作现在的代码如下所示:

- (void) drawRect:(CGRect)rect { 
//// General Declarations 
CGContextRef context = UIGraphicsGetCurrentContext(); 

//// Shadow Declarations 
CGSize shadowOffset = CGSizeMake(0, 1); 
CGFloat shadowBlurRadius = 2; 

//// Abstracted Graphic Attributes 
CGRect roundedRectangleFrame = CGRectMake(2, 0, rect.size.width - 4, rect.size.height - 2); 


//// Rounded Rectangle Drawing 
UIBezierPath* roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect: roundedRectangleFrame cornerRadius: 2]; 
CGContextSaveGState(context); 
CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.3].CGColor); 
[[UIColor whiteColor] setFill]; 
[roundedRectanglePath fill]; 
CGContextRestoreGState(context); 

[[UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:0.3] setStroke]; 
roundedRectanglePath.lineWidth = 0.5; 
[roundedRectanglePath stroke]; 

}