调用 removeFromSuperlayer 后 CATextLayer 仍在子层中
CATextLayer is still in sublayers after calling removeFromSuperlayer
我有一个 mapView,它有 34 个 CAShapeLayer 来渲染每个省,另外 34 个 CATextLayer 来渲染每个省的名称。我会为每个省计算它的中心。
现在我将这个mapView 添加到一个UIScrollView 中,当我缩放mapView 时,我想重新绘制CATextLayer 以使用另一个字体大小。所以缩放后,我会手动删除所有 CATextLayer 并重新绘制它们,如下所示。
但是我发现,for循环结束后,sublayer中还有一些CATextLayer,准确的说,我每次测试都有18个CATextLayer没有被移除。我从来没有遇到过这个问题,我错过了什么吗?请帮忙,谢谢。
-(void)drawLabelsWithFontSize:(CGFloat)fontSize {
int i = 0;
NSUInteger count = [self.mapView.layer.sublayers count];
for (i = 0; i < count; i++) {
CALayer *layer = self.mapView.layer.sublayers[i];
if ([layer isKindOfClass:[CATextLayer class]]) {
[layer removeFromSuperlayer];
// NSLog(@"%@, %lu",[layer class],i);
} else {
// NSLog(@"%@",[layer class]);
}
}
// at here, some CATextLayer still in self.mapView.layer.sublayers
__block typeof(self) weakSelf = self;
NSDictionary *labelNameAndLocation = [self getLabelNameAndLocationInfo];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
[labelNameAndLocation enumerateKeysAndObjectsWithOptions:NSEnumerationReverse usingBlock:^(id key, id obj, BOOL *stop) {
if ([(NSString *)key length] > 0) {
NSDictionary *location = (NSDictionary *)obj;
CATextLayer *label = [CATextLayer layer];
CGPoint caculateCenter = CGPointMake([weakSelf longitudeToCoordinate:[location[@"lng"] doubleValue]],[weakSelf latitudeToCoordinate:[location[@"lat"] doubleValue]]);
NSMutableAttributedString *text = [[NSMutableAttributedString alloc]
initWithString:key
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize],
NSParagraphStyleAttributeName:paragraphStyle,
NSForegroundColorAttributeName:[UIColor blackColor]}];
CGSize size = [text size];
[label setBounds:CGRectMake(0, 0, size.width, size.height)];
[label setString:text];
label.position = caculateCenter;
label.contentsScale = [[UIScreen mainScreen] scale];
[weakSelf.mapView.layer addSublayer:label];
}
}];
}
您犯了在删除过程中向上迭代的经典错误:
for (i = 0; i < count; i++) {
CALayer *layer = self.mapView.layer.sublayers[i];
if ([layer isKindOfClass:[CATextLayer class]]) {
[layer removeFromSuperlayer];
// NSLog(@"%@, %lu",[layer class],i);
} else {
// NSLog(@"%@",[layer class]);
}
}
更改 for
行以迭代 down:
for (i = count-1; i >= 0; i--) {
原因是,如果您首先删除子层 0,则所有其他子层都会向下移动一个索引。因此,如果您删除子层 0 并且子层 1 也是一个文本层,那么该文本层现在是子层 0 并且永远不会被删除,因为您继续到子层 1。因此,正如您非常正确地证明的那样,您最终恰好丢失了一半其中
我有点惊讶,事实上,你并没有因此而崩溃,但我猜有这么多的子层,你从来没有从数组的末端掉下来;通常会发生崩溃。
我有一个 mapView,它有 34 个 CAShapeLayer 来渲染每个省,另外 34 个 CATextLayer 来渲染每个省的名称。我会为每个省计算它的中心。
现在我将这个mapView 添加到一个UIScrollView 中,当我缩放mapView 时,我想重新绘制CATextLayer 以使用另一个字体大小。所以缩放后,我会手动删除所有 CATextLayer 并重新绘制它们,如下所示。
但是我发现,for循环结束后,sublayer中还有一些CATextLayer,准确的说,我每次测试都有18个CATextLayer没有被移除。我从来没有遇到过这个问题,我错过了什么吗?请帮忙,谢谢。
-(void)drawLabelsWithFontSize:(CGFloat)fontSize {
int i = 0;
NSUInteger count = [self.mapView.layer.sublayers count];
for (i = 0; i < count; i++) {
CALayer *layer = self.mapView.layer.sublayers[i];
if ([layer isKindOfClass:[CATextLayer class]]) {
[layer removeFromSuperlayer];
// NSLog(@"%@, %lu",[layer class],i);
} else {
// NSLog(@"%@",[layer class]);
}
}
// at here, some CATextLayer still in self.mapView.layer.sublayers
__block typeof(self) weakSelf = self;
NSDictionary *labelNameAndLocation = [self getLabelNameAndLocationInfo];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
[labelNameAndLocation enumerateKeysAndObjectsWithOptions:NSEnumerationReverse usingBlock:^(id key, id obj, BOOL *stop) {
if ([(NSString *)key length] > 0) {
NSDictionary *location = (NSDictionary *)obj;
CATextLayer *label = [CATextLayer layer];
CGPoint caculateCenter = CGPointMake([weakSelf longitudeToCoordinate:[location[@"lng"] doubleValue]],[weakSelf latitudeToCoordinate:[location[@"lat"] doubleValue]]);
NSMutableAttributedString *text = [[NSMutableAttributedString alloc]
initWithString:key
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize],
NSParagraphStyleAttributeName:paragraphStyle,
NSForegroundColorAttributeName:[UIColor blackColor]}];
CGSize size = [text size];
[label setBounds:CGRectMake(0, 0, size.width, size.height)];
[label setString:text];
label.position = caculateCenter;
label.contentsScale = [[UIScreen mainScreen] scale];
[weakSelf.mapView.layer addSublayer:label];
}
}];
}
您犯了在删除过程中向上迭代的经典错误:
for (i = 0; i < count; i++) {
CALayer *layer = self.mapView.layer.sublayers[i];
if ([layer isKindOfClass:[CATextLayer class]]) {
[layer removeFromSuperlayer];
// NSLog(@"%@, %lu",[layer class],i);
} else {
// NSLog(@"%@",[layer class]);
}
}
更改 for
行以迭代 down:
for (i = count-1; i >= 0; i--) {
原因是,如果您首先删除子层 0,则所有其他子层都会向下移动一个索引。因此,如果您删除子层 0 并且子层 1 也是一个文本层,那么该文本层现在是子层 0 并且永远不会被删除,因为您继续到子层 1。因此,正如您非常正确地证明的那样,您最终恰好丢失了一半其中
我有点惊讶,事实上,你并没有因此而崩溃,但我猜有这么多的子层,你从来没有从数组的末端掉下来;通常会发生崩溃。