将 UIView 添加到当前 UIView 后无法访问子层

Can't access sublayer after adding a UIView into current UIView

我正在绘制一堆 CAShapeLayer,所以我需要检测我正在触摸哪个,所以我使用这个

if let sublayers = self.layer.sublayers as? [CAShapeLayer]{ //get all CAShape and stored as an array
            print("loop sublayer")
            for layer in sublayers{ // go through each CAShape
                print("loop layer")
                if let path = layer.path, path.contains(currentPanPoint) { // if there is a path at that point then return, else create a path
                    print("detecting")
                    startPointOfTouchedRuler = detectWhichRuler(layer: layer)
                    if startPointOfTouchedRuler != zeroPoint{
                        //  drawCircle(point: startPointOfTouchedRuler)
                        break
                    }else{
                    }
                }
            }
        }

现在我想在每次创建 CAShapeLayer 时添加一个 UIView 以更轻松地管理和移动它们,我使用它在 CAShapeLayer 位置添加一个新的 Uiview:

  func createUIViewOutSideRuler(startPoint:CGPoint, currentPoint:CGPoint, angle: CGFloat){
        let viewWidth = distanceFromTwoPoints(startPoint, currentPoint)
        print(viewWidth)
        let view = UIView(frame: CGRect(x:currentPoint.x, y: currentPoint.y , width:  viewWidth, height: dotLineSize * 3))
        view.backgroundColor = .orange
        view.transform = CGAffineTransform(rotationAngle: angle);
        
        self.addSubview(view)
    }

添加新UIview后,获取哪个CAShapeLayer的循环根本不会触发,命令行不打印print("loop sublayer")

P/S:同样适用于Label、Button等。如果我在添加 UIView UIButton 之后 print(self.layer.sublayers as? [CAShapeLayer]),它 returns nil


快速解释:

当您执行 self.layer.sublayers as? [CAShapeLayer] 时,您假设所有 self.layer.sublayers 都是 CAShapeLayer 类型。但是,你确定,这是谁告诉你的?还有其他类型的 CALayer,默认组件可能已经附带了一些。这就是它失败的原因。这个想法是使用 compactMap() 只保留 CAShapeLayer:

let sublayers = self.layer.sublayers.compactMap { [=10=] as? [CAShapeLayer] }

详细解释:

if let sublayers = self.layer.sublayers as? [CAShapeLayer] {} else {}

else 被调用是因为 self.layer.sublayers 不可装入,它不是 [CAShapeLayer]。在我们的例子中,它们是层,所以这意味着并非所有子层都是 CAShapeLayer。 所以,让我们只保留 CAShapeLayer,而忽略另一个(CAGradientLayerCALayer 等)。 为此,我们可以使用 compactMap().

self.layer.sublayers.compactMap { aSublayer in
 
}

闭包逻辑很简单: 数组被迭代。在每次迭代中,该项目称为 aSublayer。我们做任何我们想做的事,如果需要,我们 return 一个转换后的值,一个 Int 等。 如果我们不想保留转换后的值,我们return nil,然后它会被跳过。

因为我们只想保留 CAShapeLayer 的子层,我们可以对它们使用简单的转换:

if let aSubLayerAsShapeLayer = aSubLayer as? CAShapeLayer {
    return aSubLayerAsShapeLayer
} else { //We won't keep it
    return nil
}

相当于

return aSubLayer as? CAShapeLayer

然后,通过更多的简化(来自 Single-Expression 闭包的隐式 Returns,Shorthand Argument Names,关于 doc 的更多信息),我们得到:

let sublayers = self.layer.sublayers.compactMap { [=10=] as? [CAShapeLayer] }

此外,由于“确定”有一个数组(可能为空),它不再是可选的,我们将 if let 删除为 let