我有一个有趣的问题.我想创建一个可以处理Reference类型和Nullable<T>类型的泛型类.基本上我想要的东西:
public class ClassWithNull<T>
{
public T varName = null;
}
Run Code Online (Sandbox Code Playgroud)
当然,这当然不会编译,因为并非所有类型都可以赋值为null,即不可为空的值类型.但问题是Nullable<T>价值类型,所以简单地添加where T : class并没有帮助我.我的泛型foo不是太强,但是我无法找到任何方式来说T必须是引用类型或可以为值的类型.
我必须解决这个问题的想法是创建ClassWithNull<T>一个抽象类.然后我可以添加两个子类,一个用于处理引用类型,另一个用于处理可空值类型.然后,基类中的静态工厂方法可以使用反射来确定应该构造哪个子类.就像是:
public static ClassWithNull<T> CreateClassWithNull<T>()
{
StackTrace st = new StackTrace();
Type type = st.GetFrame(1).GetMethod().GetGenericArguments()[0];
if (!type.IsValueType)
{
return new ClassWithReferenceType<T>();
}
else if (type == typeof(Nullable))
{
return new ClassWithNullableValueType<T>();
}
else
{
throw new Exception("Must provide nullable type.");
}
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是泛型是静态解决的.如果ClassWithReferenceType<U>期望U是引用类型,则new ClassWithReferenceType<T>()在工厂方法中调用是编译错误,因为T不需要是引用类型.编译器不知道运行时检查.
关于如何实现这样的事情的任何想法?
是否可以将仅在运行时知道的非可空值类型转换为可空?换一种说法:
public Type GetNullableType(Type t)
{
if (t.IsValueType)
{
return typeof(Nullable<t>);
}
else
{
throw new ArgumentException();
}
}
Run Code Online (Sandbox Code Playgroud)
显然这return条线会出错.有没有办法做到这一点?该Type.MakeGenericType方法似乎很有希望,但我不知道如何获得一个未指定的通用Type对象表示Nullable<T>.有任何想法吗?
我有一个水平堆栈视图,从左到右都有三个控件:一个自定义UIView子类(具有固有的内容大小)和两个UILabel。两个标签的配置如下:
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = false
label.adjustsFontForContentSizeCategory = true
Run Code Online (Sandbox Code Playgroud)
我将堆栈视图分布设置.fill为,三个控件的内容优先级和内容压缩优先级设置为,以便自定义视图和第一个标签的框架拥抱内容,第二个标签拉伸以填充剩余空间。看起来像这样:
|[custom view][label 1][label 2 ]|
Run Code Online (Sandbox Code Playgroud)
当我将系统文本大小调整为较大以致没有足够的水平空间来显示两个标签的全文时,就会出现我的问题。我希望在没有足够的空间显示全文时将其完全隐藏,而不是将第一个标签的文本截断为“ ...”。有什么办法可以通过自动布局来做到这一点?
感觉似乎应该有一种方法,可以使用宽度= 0约束来进行此操作,并在压缩阻力优先级周围仔细校准优先级,但是我无法完全理解如何做。
假设我有一个自定义订阅者,它请求订阅一个值,然后在收到前一个值三秒后请求一个附加值:
class MySubscriber: Subscriber {
typealias Input = Int
typealias Failure = Never
private var subscription: Subscription?
func receive(subscription: Subscription) {
print("Subscribed")
self.subscription = subscription
subscription.request(.max(1))
}
func receive(_ input: Int) -> Subscribers.Demand {
print("Value: \(input)")
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
self.subscription?.request(.max(1))
}
return .none
}
func receive(completion: Subscribers.Completion<Never>) {
print("Complete")
subscription = nil
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用它来订阅无限范围的发布者,则可以很好地处理背压,发布者每次等待 3 秒,直到收到下一个发送值的请求:
(1...).publisher.subscribe(MySubscriber())
// Prints values infinitely with ~3 seconds between each:
//
// Subscribed
// Value: 1
// Value: 2
// Value: …Run Code Online (Sandbox Code Playgroud) dispatch_apply 将调度队列作为参数,这使您可以选择在哪个队列上执行块。
我的理解是,DispatchQueue.concurrentPerform在Swift中是要替换的dispatch_apply。但是此函数不将调度队列作为参数。搜寻之后,我发现了这个GCD教程,其中包含以下代码:
let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: addresses.count) { index in
// do work here
}
Run Code Online (Sandbox Code Playgroud)
并说明:
此实现包括一个奇怪的代码行:
let _ = DispatchQueue.global(qos: .userInitiated)。调用此命令会导致GCD对.userInitiated并发调用使用具有服务质量的队列。
我的问题是,这实际上可以用来指定QoS吗?如果是这样,怎么办?
对于我来说,没有办法为此指定队列是有道理的,因为在这种情况下,串行队列没有意义,并且鉴于这是同步阻塞功能,因此只有最高的QoS才有意义。但是我找不到任何文档来说明为什么可以用来指定队列,dispatch_apply而用来不可能(?)DispatchQueue.concurrentPerform。
c# ×2
reflection ×2
swift ×2
autolayout ×1
backpressure ×1
cocoa-touch ×1
combine ×1
generics ×1
ios ×1
nullable ×1