如何创建一个包含多个CALayer实例的NSArray(这些实例都具有相同的frame、contents等属性)?
背景:创建CALayer需要一定的开销,因此我想在一个类的init方法中创建多个CALayer(它们共享同样的属性),以便稍后在该类中使用。
如何创建一个包含多个CALayer实例的NSArray(这些实例都具有相同的frame、contents等属性)?
背景:创建CALayer需要一定的开销,因此我想在一个类的init方法中创建多个CALayer(它们共享同样的属性),以便稍后在该类中使用。
我尚未特别尝试过这个方法用于CALayer
,但我知道你可以通过利用NSCoding
来执行深复制:
CALayer *layer = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:layer]];
然而我不确定复制它们如何真正有助于性能。
-(id)copy
方法。我不知道为什么。但是自己编写一个并不难,只需要创建一个CALayer类别并编写自己的copy方法即可。你只需要实例化并手动从原始对象获取公共ivars/属性并设置到新的副本中。不要忘记调用[super copy]
。MaxGabriel的最佳答案的更新链接。
Objective-C
CALayer *layer1;
CALayer *layer2;
// Set up layer1's specifics.
layer2 = [NSKeyedUnarchiver unarchivedObjectOfClass:[CALayer class]
fromData:[NSKeyedArchiver archivedDataWithRootObject:layer1 requiringSecureCoding:NO error:nil] error:nil];
而且使用 Swift。
let layer1: CALayer?
var layer2: CALayer? = nil
// Set up layer1's specifics
do {
layer2 = try NSKeyedUnarchiver.unarchivedObject(
ofClass: CALayer.self,
from: try NSKeyedArchiver.archivedData(withRootObject: layer1, requiringSecureCoding: false))
} catch {
// It failed. Do something.
}
这就是为什么要使用NSProxy。您所描述的是一个常见的情况,可以从中派生出任意数量的设计模式。
《Pro Objective-C Design Patterns for iOS》提供了解决您所描述问题的方案;请阅读第3章:原型模式。以下是摘要定义:
原型模式指定使用原型实例创建对象的类型,通过复制此实例来创建新对象。
虽然对于你的用例来说最好使用CAReplicatorLayer
,
但其他人可能确实需要复制CALayer
,所以我在这里写了另一个答案。
(因为CARenderer
的原因,我不得不复制)
我也尝试过使用NSKeyedArchiver
,它基本上可以工作,但对于复杂的CALayer
,有些功能会出现问题
(对我来说,是带有滤镜的蒙版)
实现非常简单。
CALayer
。这是一个关于CAShapeLayer
的示例:
extension CALayer {
func deepCopy() -> CAShapeLayer {
let layer = CAShapeLayer()
layer.frame = frame
layer.bounds = bounds
layer.filters = filters
layer.contents = contents
layer.contentsScale = contentsScale
layer.masksToBounds = masksToBounds
//add or remove lines for your need
if let self = self as? CAShapeLayer {
layer.path = self.path?.copy()
layer.lineCap = self.lineCap
layer.lineJoin = self.lineJoin
layer.lineWidth = self.lineWidth
layer.fillColor = self.fillColor
layer.strokeColor = self.strokeColor
//add or remove lines for your need
}
layer.mask = mask?.deepCopy()
layer.sublayers = sublayers?.map { $0.deepCopy() }
return layer
}
}
我在我的程序中做了完全相同的事情。
在初始化中:
self.turrets = [NSMutableArray array];
for (count = 0; count < kMaxTurrets; count++)
[self spawnTurret];
evTurret* aTurret = [[[evTurret alloc] init] autorelease];
CGImageRef theImage = [self turretContents];
aTurret.contents = theImage;
double imageHeight = CGImageGetHeight(theImage);
double imageWidth = CGImageGetWidth(theImage);
double turretSize = 0.06*(mapLayer.bounds.size.width + mapLayer.bounds.size.height)/2.0;
aTurret.bounds = CGRectMake(-turretSize*0.5, turretSize*0.5, turretSize*(imageWidth/imageHeight), turretSize);
aTurret.hidden = YES;
[mapLayer addSublayer:aTurret];
[self.turrets addObject:aTurret];