我正在尝试创建一个API,允许调用者将void rotateClockwise( int degree ) {
int currentDegree = getDegree();
int desiredDegree = currentDegree + degree;
if( desiredDegree > 359 ) {
desiredDegree -= 359;
}
do {
newDegree = getDegree(); // Returns current degree
desiredDegreeSINE = sin(desiredDegree * (PI/180));
currentDegreeSINE = sin(newDegree * (PI/180));
if( desiredDegreeSINE > 0 && currentDegreeSINE < 0 ) {
newDegree = newDegree - 360;
}
if( newDegree >= desiredDegree ) {
// Stop rotating
break;
} else {
// Keep rotating
}
} while(true);
}
的子类和一个块传递给一个函数,然后接收器将使用给定的UIView
子类实例调用该块和另一个论点。我已经解决了这个问题,所以它在游乐场里运行:
UIView
然后呼叫者将使用import UIKit
struct SomeStruct<T where T: UIView> {
let view: T
let block: ((T, Int) -> Void)
//some computed variables here that rely on T being a UIView
}
class SomeClass {
var data: SomeStruct<UIView>? //Ideally, SomeStruct<? where ? : UIView>
func doSomethingLater<V where V: UIView>(view: V, block: ((V, Int) -> Void)) {
//Cannot convert value of type '(V, Int) -> Void' to expected argument type '(_, Int) -> Void'
self.data = SomeStruct(view: view, block: block)
}
}
,如下所示:
SomeClass
我想要限制let c = SomeClass()
let label = UILabel()
c.doSomethingLater(b) { (label, idx) in
//l is type UILabel
}
let button = UIButton(type: .Custom)
c.doSomethingLater(b) { (button, idx) in
//b is type UIButton
}
而不是UIView
本身的子类的原因是,在块内,调用者不需要将参数强制转换为它的原始类型
所以,我的问题是:在声明变量的类型时,有没有办法使用UIView
子句?
答案 0 :(得分:1)
我可以看到实现这一目标的多种方法。使用哪一个取决于您,具体取决于您希望如何组织代码。
让SomeClass
本身通用:
class SomeClass<V: UIView> {
var data: SomeStruct<V>?
...
}
使SomeStruct符合协议(使用 no 关联类型),该协议仅公开UIView,因此您仍然可以编写计算属性:
protocol SomeStructType {
var view: UIView { get }
}
extension SomeStructType {
// add computed properties based on self.view...
}
struct ConcreteStruct<V: UIView>: SomeStructType {
let realView: V
let block: (T, Int) -> Void
var view: UIView { return realView } // satisfy the protocol
}
class SomeClass {
var data: SomeStructType?
...
func doSomethingLater<V: UIView>(view: V, block: (V, Int) -> Void) {
data = ConcreteStruct(realView: view, block: block)
}
}
而不是结构,使用非泛型类的泛型子类(这与#2非常相似)
class SomeData {
var view: UIView { fatalError("abstract method") }
...
}
class ConcreteData<V: UIView>: SomeData {
let realView: V
let block: (V, Int) -> Void
override var view: UIView { return realView } // override the getter
init(view: V, block: (V, Int) -> Void) { ... }
}
class SomeClass {
var data: SomeData?
...
func doSomethingLater<V: UIView>(view: V, block: (V, Int) -> Void) {
data = ConcreteData(realView: view, block: block)
}
}
答案 1 :(得分:-2)
你根本不需要SomeClass
struct S<T> {
let a: T
let b: (T, Int) -> Void
}
let s = S(a: "a") { (i, j) in
// see, that a is NOT accessible here!!!!
print("1:",i,j)
}
s.b("b", 1) // compiler take care about types, so (String,Int) is the only option
// to be able change b later !!!!!
struct S1<T> {
let a: T
var b: (T, Int) -> Void
}
var s1 = S1(a: 100) { _ in }
s1.b = { label, index in
print("2:",s1, label, index)
}
s1.b(200,2)
class C {
var i: Int = 0
}
let c:C? = C()
var s2 = S1(a: c) { _ in } // so later i can modify c
s2.b = { label, index in
s2.a?.i = index
}
print("3:",c, c?.i)
s2.b(nil, 100)
print("4:",c, c?.i)
打印
1: b 1
2: S1<Int>(a: 100, b: (Function)) 200 2
3: Optional(C) Optional(0)
4: Optional(C) Optional(100)
或
let c2 = C()
c2.i = 200
// modify c.i to max of c2.i and some value
s2.b = { c, i in
if let j = c?.i {
s2.a?.i = max(j,i)
}
}
s2.b(c2, 50) // s2 still modify c
print("5:",c, c?.i)
s2.b(c2, 250) // s2 still modify c
print("6:",c, c?.i)
打印
5: Optional(C) Optional(200)
6: Optional(C) Optional(250)