由_layer.contents = (__bridge id)image.CGImage想到的

先从这段代码说起

UIImage *image = [UIImage imageNamed:@"xxx.png"] ;
_layer.contents = (__bridge id)image.CGImage ;

我曾经考虑要不要保持image的强引用以防其被释放,因为我的理解是:image被释放时,image.CGImage就会被释放了,然而事实是image.CGImage是不会被释放的,因为_layer.contents保持了CGImage的强引用,在CALayercontents属性被定义成@property(strong) id contents;,不过我还是怀疑这个strong会起作用么?理由是,image.CGImageCGImageRef类型的,而CGImageRef是一个指针:typedef struct CGImage *CGImageRef;,我查了一下文档,发现CGImageRef不是Toll Free Bridging。_layer.contents = (__bridge id)image.CGImage ;,在这段代码执行时会给image.CGImage发送retain消息,问题是image.CGImage会被retain么?

先说结论吧,答案是会被retain,Core Foundation也是采用引用计数的机制,并且CGImageRef跟Objective-C中的NSObject *是类似的,既是CGImageNSObject类似。

当我把_layer.contents用NSLog打印出来之后,事情变得明确一些了,日志是这样:
NSLog(@"_layer.contents %@", [(__bridge id)image.CGImage class]);
结果是:
_layer.contents __NSCFType
日志说明,CGImage是有isa指针的,并且指向了一个名为__NSCFType的对象,通过调用这个函数class_getSuperclass(class),我看到__NSCFType的父类是NSObject,所以CGImage可以被看做是NSObject对象,或者说所有的Core Foundation中的类型都可以看做NSObject对象。这里我推荐看一下MikeAsh的文章,看过之后你也应该明白了。

总结一下,我产生这个疑问的原因是没搞明白Core Foundation对象的结构,虽然不是所有的Core Foundation的类型都是Toll Free Bridging的,但是他们都有着与NSObject类似的内存结构,都可以对其retain或者release。正因为这样,我们才可以对其应用__bridge或者__bridge_transfer,你可以尝试随便对一个int *类型的值应用__bridge id转换,编译器是不允的。

int *a ;
_layer.contents = (__bridge id)a ;

而下面的代码就可以编译通过:

struct {
    void *isa ;
} SimulateNSObject ;

- (void)fun
{
    struct SimulateNSObject *a ;
    _layer.contents = (__bridge id)a ; // 允许
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 `CAEmitterLayer` 可以很方便地实现各种粒子效果,下面是使用 `CAEmitterLayer` 实现不同天气效果的示例代码: ### 小雨效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let rain = makeRainCell() emitterLayer.emitterCells = [rain] view.layer.addSublayer(emitterLayer) func makeRainCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "raindrop")?.cgImage cell.birthRate = 50 cell.lifetime = 2 cell.velocity = 100 cell.velocityRange = 50 cell.yAcceleration = 500 cell.scale = 0.2 cell.scaleRange = 0.1 cell.emissionLongitude = -.pi cell.emissionRange = .pi / 4 return cell } ``` ### 中雨效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let rain = makeRainCell() emitterLayer.emitterCells = [rain] view.layer.addSublayer(emitterLayer) func makeRainCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "raindrop")?.cgImage cell.birthRate = 100 cell.lifetime = 2 cell.velocity = 150 cell.velocityRange = 50 cell.yAcceleration = 500 cell.scale = 0.3 cell.scaleRange = 0.1 cell.emissionLongitude = -.pi cell.emissionRange = .pi / 4 return cell } ``` ### 暴雨效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let rain = makeRainCell() emitterLayer.emitterCells = [rain] view.layer.addSublayer(emitterLayer) func makeRainCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "raindrop")?.cgImage cell.birthRate = 200 cell.lifetime = 2 cell.velocity = 200 cell.velocityRange = 50 cell.yAcceleration = 500 cell.scale = 0.4 cell.scaleRange = 0.1 cell.emissionLongitude = -.pi cell.emissionRange = .pi / 4 return cell } ``` ### 下雪效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let snow = makeSnowCell() emitterLayer.emitterCells = [snow] view.layer.addSublayer(emitterLayer) func makeSnowCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "snowflake")?.cgImage cell.birthRate = 50 cell.lifetime = 10 cell.velocity = 50 cell.velocityRange = 20 cell.yAcceleration = 10 cell.scale = 0.2 cell.scaleRange = 0.1 cell.emissionLongitude = -.pi cell.emissionRange = .pi / 4 return cell } ``` ### 沙尘暴效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let dust = makeDustCell() emitterLayer.emitterCells = [dust] view.layer.addSublayer(emitterLayer) func makeDustCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "dust")?.cgImage cell.birthRate = 100 cell.lifetime = 5 cell.velocity = 100 cell.velocityRange = 50 cell.yAcceleration = 10 cell.scale = 0.2 cell.scaleRange = 0.1 cell.emissionLongitude = -.pi cell.emissionRange = .pi / 4 return cell } ``` ### 高温效果 ```swift let emitterLayer = CAEmitterLayer() emitterLayer.emitterShape = .line emitterLayer.emitterSize = CGSize(width: view.bounds.width, height: 1) let fire = makeFireCell() emitterLayer.emitterCells = [fire] view.layer.addSublayer(emitterLayer) func makeFireCell() -> CAEmitterCell { let cell = CAEmitterCell() cell.contents = UIImage(named: "fire")?.cgImage cell.birthRate = 100 cell.lifetime = 1 cell.velocity = 50 cell.velocityRange = 20 cell.yAcceleration = -50 cell.scale = 0.2 cell.scaleRange = 0.1 cell.color = UIColor.orange.cgColor cell.emissionLongitude = .pi cell.emissionRange = .pi / 4 return cell } ``` 以上代码中,每个天气效果都是通过创建一个 `CAEmitterLayer` 和一个或多个 `CAEmitterCell` 来实现的。在每个 `CAEmitterCell` 中,可以设置粒子的属性,例如:出生率、寿命、速度、加速度、缩放比例、颜色等等。可以根据具体需求自由调整每个属性的值,以达到想要的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值