swift class 属性 行为
swift class property behavior
感谢您帮助我们弄清楚 class 中的 属性 会发生什么。
class CustomCorner: MDCCornerTreatment{
var radius: CGFloat = 12;
convenience init(radius: CGFloat) {
self.init();
self.radius = radius;
print("Corner initialized with radius=\(self.radius)");
}
override func pathGeneratorForCorner(withAngle angle: CGFloat) -> MDCPathGenerator {
print("entering pathGeneratorForCorner with radius \(self.radius)")
let path = MDCPathGenerator(start: CGPoint(x: 0, y: radius))
print("continuing pathGeneratorForCorner with radius \(radius)")
path.addLine(to: CGPoint(x: radius, y: radius))
path.addLine(to: CGPoint(x: radius, y: 0))
return path
}
}
与此代码一起使用时:
let mdcRectangleShape = MDCRectangleShapeGenerator()
let customCorner = CustomCorner(radius: 8)
print("step 1 radio=\(customCorner.radius)")
customCorner.radius = 5
print("step 2 radio=\(customCorner.radius)")
mdcRectangleShape.setCorners(customCorner)
print("step 3 radio=\(customCorner.radius)")
let _ = customCorner.pathGeneratorForCorner(withAngle: 10)
nextButton.shapeGenerator = mdcRectangleShape
print("step 4 radio=\(customCorner.radius)")
我得到以下输出:
Corner initialized with radius=8.0
step 1 radio=8.0
step 2 radio=5.0
step 3 radio=5.0
entering pathGeneratorForCorner with radius 5.0
continuing pathGeneratorForCorner with radius 5.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
step 4 radio=5.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
这里我使用 Material 设计组件 iOS,尽管问题看起来更像是 Swift 问题。
这是我的调试代码,我故意插入不同的值来显示问题。
无论我如何设置半径 属性,一旦在覆盖函数 pathGeneratorForCorner:withAngle 中使用它,它只使用分配的第一个值。
在我看来,某处有一个环境捕获,尽管它不是闭包,因为它是一个覆盖函数。 (函数可以捕获环境吗?如果可以,我该如何避免?)
到目前为止我所做的无济于事:
- 将值包装在 Class 中。我知道这是多余的,因为 CGFloat 已经是一个 class,但它是一个疯狂的镜头。
- 在第一步之后,我直接赋值了。它已更改,如步骤 2 所示,但在函数内部,使用的值是分配的第一个值,12
- 我认为会是一个杀手,我在指向 属性 的函数中创建了一个 UnsafePointer,令我惊讶的是,它保留了第一个值(好像 属性 有一个第二记忆,它没有)
- 我尝试使用一个常量 (let),但它被请求调用自身的便利初始化程序搞得一团糟,然后一个指定的初始化程序进来了,只是抱怨它正在调用一个未定义的初始化程序,并且各种问题,其中包括调用 init 的顺序和正在初始化的 属性。如果听起来很乱,那就是。
- 我也尝试了一个可选值,但它也没有用。
非常感谢您的帮助。
问候。
阿尔弗雷多.
所有现代编程都是object-based编程。这是关于 object-based 编程的事情;一个对象类型可以有多个实例,并且每个这样的实例都单独维护其自己的实例属性值。
至此,您的代码和输出之间的关系已经很清楚了:
let mdcRectangleShape = MDCRectangleShapeGenerator()
let customCorner = CustomCorner(radius: 8)
print("step 1 radio=\(customCorner.radius)")
customCorner.radius = 5
print("step 2 radio=\(customCorner.radius)")
mdcRectangleShape.setCorners(customCorner)
print("step 3 radio=\(customCorner.radius)")
let _ = customCorner.pathGeneratorForCorner(withAngle: 10)
nextButton.shapeGenerator = mdcRectangleShape
你的输出是:
Corner initialized with radius=8.0
step 1 radio=8.0
step 2 radio=5.0
step 3 radio=5.0
entering pathGeneratorForCorner with radius 5.0
continuing pathGeneratorForCorner with radius 5.0
是的,嗯,这就是我们期望看到的。您将半径设置为 5
,它保持 5
。
好的,所有其他输出是从哪里来的?
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
这些将来自某些 other CustomCorner 实例,您在其中 not 将 radius
设置为 5
.它仍然是默认值,12
,你初始化它的方式:
var radius: CGFloat = 12;
至于那些其他实例来自哪里,我不知道。你没有显示足够的代码让我知道。
要确认这一点,请继续打印 CustomCorner 对象 本身 。它将打印其内存地址,这是一个唯一标识符。您会看到您有多个 不同的 CustomCorner 对象。
正如马特的回答中已经提到的,显示的 entering pathGeneratorForCorner with radius 12.0
是您的 customCorner
.
的副本
从GitHub of Material iOS开始,[MDCRectangleShapeGenerator setCorners:]
实现如下:
- (void)setCorners:(MDCCornerTreatment *)cornerShape {
self.topLeftCorner = [cornerShape copy];
self.topRightCorner = [cornerShape copy];
self.bottomRightCorner = [cornerShape copy];
self.bottomLeftCorner = [cornerShape copy];
}
事实上,它为 setCorners:
.
复制了 4 个对象
您的 CustomCorner
继承了 MDCCornerTreatment
,符合 NSCopying
。
MDCCornerTreatment
实现 copyWithZone:
需要符合 NSCopying
,但实现不知道其子类的属性。
您可能需要通过覆盖 CustomCorner
.
中的 copy(with:)
来修改此默认复制行为
class CustomCorner: MDCCornerTreatment{
var radius: CGFloat = 12;
convenience init(radius: CGFloat) {
self.init();
self.radius = radius;
print("Corner initialized with radius=\(self.radius)");
}
override func copy(with zone: NSZone? = nil) -> Any {
let newCopy = super.copy(with: zone) as! CustomCorner
newCopy.radius = self.radius
return newCopy
}
//...
}
感谢您帮助我们弄清楚 class 中的 属性 会发生什么。
class CustomCorner: MDCCornerTreatment{
var radius: CGFloat = 12;
convenience init(radius: CGFloat) {
self.init();
self.radius = radius;
print("Corner initialized with radius=\(self.radius)");
}
override func pathGeneratorForCorner(withAngle angle: CGFloat) -> MDCPathGenerator {
print("entering pathGeneratorForCorner with radius \(self.radius)")
let path = MDCPathGenerator(start: CGPoint(x: 0, y: radius))
print("continuing pathGeneratorForCorner with radius \(radius)")
path.addLine(to: CGPoint(x: radius, y: radius))
path.addLine(to: CGPoint(x: radius, y: 0))
return path
}
}
与此代码一起使用时:
let mdcRectangleShape = MDCRectangleShapeGenerator()
let customCorner = CustomCorner(radius: 8)
print("step 1 radio=\(customCorner.radius)")
customCorner.radius = 5
print("step 2 radio=\(customCorner.radius)")
mdcRectangleShape.setCorners(customCorner)
print("step 3 radio=\(customCorner.radius)")
let _ = customCorner.pathGeneratorForCorner(withAngle: 10)
nextButton.shapeGenerator = mdcRectangleShape
print("step 4 radio=\(customCorner.radius)")
我得到以下输出:
Corner initialized with radius=8.0
step 1 radio=8.0
step 2 radio=5.0
step 3 radio=5.0
entering pathGeneratorForCorner with radius 5.0
continuing pathGeneratorForCorner with radius 5.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
step 4 radio=5.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
这里我使用 Material 设计组件 iOS,尽管问题看起来更像是 Swift 问题。
这是我的调试代码,我故意插入不同的值来显示问题。
无论我如何设置半径 属性,一旦在覆盖函数 pathGeneratorForCorner:withAngle 中使用它,它只使用分配的第一个值。
在我看来,某处有一个环境捕获,尽管它不是闭包,因为它是一个覆盖函数。 (函数可以捕获环境吗?如果可以,我该如何避免?)
到目前为止我所做的无济于事:
- 将值包装在 Class 中。我知道这是多余的,因为 CGFloat 已经是一个 class,但它是一个疯狂的镜头。
- 在第一步之后,我直接赋值了。它已更改,如步骤 2 所示,但在函数内部,使用的值是分配的第一个值,12
- 我认为会是一个杀手,我在指向 属性 的函数中创建了一个 UnsafePointer,令我惊讶的是,它保留了第一个值(好像 属性 有一个第二记忆,它没有)
- 我尝试使用一个常量 (let),但它被请求调用自身的便利初始化程序搞得一团糟,然后一个指定的初始化程序进来了,只是抱怨它正在调用一个未定义的初始化程序,并且各种问题,其中包括调用 init 的顺序和正在初始化的 属性。如果听起来很乱,那就是。
- 我也尝试了一个可选值,但它也没有用。
非常感谢您的帮助。
问候。
阿尔弗雷多.
所有现代编程都是object-based编程。这是关于 object-based 编程的事情;一个对象类型可以有多个实例,并且每个这样的实例都单独维护其自己的实例属性值。
至此,您的代码和输出之间的关系已经很清楚了:
let mdcRectangleShape = MDCRectangleShapeGenerator()
let customCorner = CustomCorner(radius: 8)
print("step 1 radio=\(customCorner.radius)")
customCorner.radius = 5
print("step 2 radio=\(customCorner.radius)")
mdcRectangleShape.setCorners(customCorner)
print("step 3 radio=\(customCorner.radius)")
let _ = customCorner.pathGeneratorForCorner(withAngle: 10)
nextButton.shapeGenerator = mdcRectangleShape
你的输出是:
Corner initialized with radius=8.0
step 1 radio=8.0
step 2 radio=5.0
step 3 radio=5.0
entering pathGeneratorForCorner with radius 5.0
continuing pathGeneratorForCorner with radius 5.0
是的,嗯,这就是我们期望看到的。您将半径设置为 5
,它保持 5
。
好的,所有其他输出是从哪里来的?
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
entering pathGeneratorForCorner with radius 12.0
continuing pathGeneratorForCorner with radius 12.0
这些将来自某些 other CustomCorner 实例,您在其中 not 将 radius
设置为 5
.它仍然是默认值,12
,你初始化它的方式:
var radius: CGFloat = 12;
至于那些其他实例来自哪里,我不知道。你没有显示足够的代码让我知道。
要确认这一点,请继续打印 CustomCorner 对象 本身 。它将打印其内存地址,这是一个唯一标识符。您会看到您有多个 不同的 CustomCorner 对象。
正如马特的回答中已经提到的,显示的 entering pathGeneratorForCorner with radius 12.0
是您的 customCorner
.
从GitHub of Material iOS开始,[MDCRectangleShapeGenerator setCorners:]
实现如下:
- (void)setCorners:(MDCCornerTreatment *)cornerShape {
self.topLeftCorner = [cornerShape copy];
self.topRightCorner = [cornerShape copy];
self.bottomRightCorner = [cornerShape copy];
self.bottomLeftCorner = [cornerShape copy];
}
事实上,它为 setCorners:
.
您的 CustomCorner
继承了 MDCCornerTreatment
,符合 NSCopying
。
MDCCornerTreatment
实现 copyWithZone:
需要符合 NSCopying
,但实现不知道其子类的属性。
您可能需要通过覆盖 CustomCorner
.
copy(with:)
来修改此默认复制行为
class CustomCorner: MDCCornerTreatment{
var radius: CGFloat = 12;
convenience init(radius: CGFloat) {
self.init();
self.radius = radius;
print("Corner initialized with radius=\(self.radius)");
}
override func copy(with zone: NSZone? = nil) -> Any {
let newCopy = super.copy(with: zone) as! CustomCorner
newCopy.radius = self.radius
return newCopy
}
//...
}