CAGradientLayer 没有从视图中删除自我

Posted

技术标签:

【中文标题】CAGradientLayer 没有从视图中删除自我【英文标题】:CAGradientLayer not removing self from view 【发布时间】:2016-03-02 18:04:37 【问题描述】:

我创建一个CAGradientLayer 并将其添加到UIView

CAGradientLayer *layer = [UIColor lightBlueSpreadGradient];
layer.frame = self.contentView.bounds;
layer.cornerRadius = self.contentView.layer.cornerRadius;
self.gradientLayer = layer;

[self.contentView.layer insertSublayer:layer atIndex:0];

我保留了对它的引用,以便以后删除它:

[self.gradientLayer removeFromSuperlayer];

但它实际上并没有删除自己。我知道它被调用了,取消选择方法中的其他所有内容都按预期工作:

-(void)setIsActive:(BOOL)isActive 
    _isActive = isActive;

    if (_isActive) 
        CAGradientLayer *layer = [UIColor lightBlueSpreadGradient];
        layer.frame = self.contentView.bounds;
        layer.cornerRadius = self.contentView.layer.cornerRadius;
        self.gradientLayer = layer;
        DLog(@"inserting self.gradientLayer: %@", self.gradientLayer);

        [self.contentView.layer insertSublayer:layer atIndex:0];
    
    else 
        DLog(@"is active is false");
        DLog(@"removing overlay");

        DLog(@"self.gradientLayer: %@", self.gradientLayer);
        [self.gradientLayer removeFromSuperlayer];

    

日志:

DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | inserting self.gradientLayer: <CAGradientLayer: 0x7e26cce0>
DEBUG | -[DatasetTrayCell setIsActive:] | is active is false
DEBUG | -[DatasetTrayCell setIsActive:] | removing overlay
DEBUG | -[DatasetTrayCell setIsActive:] | removing self.gradientLayer: <CAGradientLayer: 0x7e26cce0>

点击手势:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapDectected)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;

[self addGestureRecognizer:singleTap];

检测到单击的方法:

-(void)singleTapDectected 
    DLog(@"tap detected");

    if (self.isActive) 
        self.isActive = NO;
    
    else 
        self.isActive = YES;
    


日志:

DEBUG | -[DatasetTrayCell singleTapDectected] | tap detected

知道为什么它不会删除吗?

编辑:

好的,我找到了问题,但我不明白为什么会出现问题。所以我设置isActive的完整方法:

-(void)setIsActive:(BOOL)isActive 
    DLog(@"setting isActive");

    _isActive = isActive;

    if (_isActive) 
        if ([self.delegate respondsToSelector:@selector(datasetTrayCell:displayWithCompletionBlock:)]) 
            [self.delegate datasetTrayCell:self displayWithCompletionBlock:^
                CAGradientLayer *layer = [UIColor lightBlueSpreadGradient];
                layer.frame = self.contentView.bounds;
                layer.cornerRadius = self.contentView.layer.cornerRadius;
                self.gradientLayer = layer;
                DLog(@"inserting self.gradientLayer: %@", self.gradientLayer);

                [self.contentView.layer insertSublayer:layer atIndex:0];
                DLog(@"self.gradientLayer.superlayer: %@", self.gradientLayer.superlayer);
                DLog(@"self.contentView.layer.sublayers: %@", self.contentView.layer.sublayers);

            ];
        
    
    else 
        if ([self.delegate respondsToSelector:@selector(datasetTrayCell:removeWithCompletionBlock:)]) 
            [self.delegate datasetTrayCell:self removeWithCompletionBlock:^
                DLog(@"self.contentView.layer.sublayers: %@", self.contentView.layer.sublayers);
                [self.gradientLayer removeFromSuperlayer];
                DLog(@"self.gradientLayer.superlayer: %@", self.gradientLayer.superlayer);
                DLog(@"removing self.gradientLayer: %@", self.gradientLayer);
            ];
        
        else 
            DLog(@"delegate does not respond to removeOverlayWithCompletionBlock");
        
    

CAGradientLayer 在块中创建的事实导致它被创建了两次:

DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | inserting self.gradientLayer: <CAGradientLayer: 0x787bdc80>
DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | self.gradientLayer.superlayer: <CALayer: 0x7db473f0>
DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | self.contentView.layer.sublayers: (
    "<CAGradientLayer: 0x787bdc80>",
    "<CALayer: 0x787bd750>"
)

又一次:

DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | inserting self.gradientLayer: <CAGradientLayer: 0x78631ce0>
DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | self.gradientLayer.superlayer: <CALayer: 0x7db473f0>
DEBUG | __31-[DatasetTrayCell setIsActive:]_block_invoke | self.contentView.layer.sublayers: (
    "<CAGradientLayer: 0x78631ce0>",
    "<CAGradientLayer: 0x787bdc80>",
    "<CALayer: 0x787bd750>"
)

一旦我从块中删除了那段代码,它就会正常运行(它只会创建 1 个渐变):

-(void)setIsActive:(BOOL)isActive 
    DLog(@"setting isActive");

    _isActive = isActive;

    if (_isActive) 
        CAGradientLayer *layer = [UIColor lightBlueSpreadGradient];
        layer.frame = self.contentView.bounds;
        layer.cornerRadius = self.contentView.layer.cornerRadius;
        self.gradientLayer = layer;

        [self.contentView.layer insertSublayer:layer atIndex:0];

        if ([self.delegate respondsToSelector:@selector(datasetTrayCell:displayWithCompletionBlock:)]) 
            [self.delegate datasetTrayCell:self displayWithCompletionBlock:^
            ];
        
    
    else 
        [self.gradientLayer removeFromSuperlayer];

        if ([self.delegate respondsToSelector:@selector(datasetTrayCell:removeWithCompletionBlock:)]) 
            [self.delegate datasetTrayCell:self removeWithCompletionBlock:^
            ];
        
    

为什么会发生这种情况,我还不确定。

【问题讨论】:

你能显示日志输出吗?不是我不相信你什么的,而是…… 哦,还有:这是否偶然发生在表格视图的单元格中?如果是这样,您是否还记得考虑到细胞被重复使用的事实? 将添加日志,不,这是我创建的自定义子类UIView“单元格”,用于放置在UIScrollView 嗯。好吧,我向你保证removeFromSuperlayer 确实删除了该层。您是否尝试过在该例程中放置断点?也许事情并没有按照你的预期进行。也许你不小心多次添加了渐变,所以现在渐变被移除了,但它后面还有另一个剩余的渐变。无论问题是什么,它似乎都没有出现在您在此处显示的代码中...... 宾果游戏,我认为您在这里有所作为。我查看 self.contentView.layer.sublayers 并且那里仍然存在不应该的渐变。看起来正在添加 2 个渐变。看起来该方法被调用了两次,因此添加了 2 个渐变并保持 1 个被引用。感谢您帮助我找到问题。 【参考方案1】:

所以渐变失去了对其插入位置的引用。但我不知道如何或为什么。

这不是“失去参考”。您似乎对self.gradientLayer 有强烈的引用。你已经从它的超层中删除了self.gradientLayer。但是您在强参考中保留了它。现在你要它的超层,很自然,它没有;你删除了它。因此,在界面中看到的渐变层与您正在与之交谈的渐变层相同。这个故事中有(至少)两个渐变层。事情已经不同步了,这让你感到困惑。但我向你保证,该层并没有表现异常。

【讨论】:

好的,失去参考是错误的术语。我听从了你的建议,还有一些额外的渐变没有被删除。我会更新的。 是的,你是对的。我删除了该层,然后检查了它的超层,这是非常愚蠢的事情。我应该在移除它之前检查它的超层。根据您的建议,看看是否有额外的渐变没有被删除,帮助我找出问题所在。我不明白为什么这是一个问题,但我确实有解决办法。谢谢! 对不起,我有一个坏习惯,即投票并认为是接受。【参考方案2】:

尝试这样做:

for (CALayer *layer in self.contentView.layer.sublayers) 
    if([layer isKindOfClass:[GradientLayer class]])
    
        [layer removeFromSuperlayer];

    

【讨论】:

以上是关于CAGradientLayer 没有从视图中删除自我的主要内容,如果未能解决你的问题,请参考以下文章

如何从它的超级层中删除 CAGradientLayer

没有显示 CAGradientLayer?

如何在 iOS swift 运行时更新 CAGradientLayer 颜色?

为啥我不能在 ARC 中使用自定义颜色创建 CAGradientLayer?

CAGradientLayer:其他 UIObjects 没有出现

iPhone iOS自定义UIButton与CAGradientLayer,如何让它指示触摸?