除了具有协议扩展的语法之外:
protocol P {}
extension P where Self : UIView {}
Run Code Online (Sandbox Code Playgroud)
...我偶然发现你可以在协议本身使用相同的where子句:
protocol P where Self : UIView {}
Run Code Online (Sandbox Code Playgroud)
请注意,这是不一样的where子句限制一个通用的协议,并没有自己做P上的通用协议.
我的实验似乎表明,这里只能使用冒号,冒号之后的东西必须是类或协议(可能是通用的).
我变得很好奇:这是怎么逃避我的注意的?所以我去寻找它何时出现的证据.在Swift 3.0中,前一种语法是合法的,但不是后者.在Swift 3.3中,两者都是合法的.所以后一种语法必须在Swift 3.2之类的东西中悄然引入.我说"悄悄地",因为我在发行说明中找不到任何关于它的内容.
第二种语法是什么?它看起来只是一种方便的方法来确保没有其他类型可以采用这个协议吗?Swift标头似乎没有使用它.
嗨那里=)我刚刚面临一个设计问题,我需要(基本上)做以下事情:
我要注入一些代码上viewWillAppear:的任何UIViewController符合协议的子类MyProtocol.在代码中解释:
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController where Self: MyProtocol //<-----compilation error
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
Run Code Online (Sandbox Code Playgroud)
这里的主要问题是我需要UIVIewController扩展中的两件事:
MyProtocol和UIViewControllerAPIUIViewController方法initialize() …我看到了很多以下格式的例子
extension Protocolname where Self: UIViewController
Run Code Online (Sandbox Code Playgroud)
什么是where Self协议扩展.我找不到关于此的文档.
我不明白为什么我的代码不起作用.这里是:
class Test: NSURLSessionDataDelegate {
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if(error == nil) {
print("Hallo")
} else {
print(error?.userInfo)
}
}
func createRequest() {
let dictionary = [
"mailAddress":"foo@example.com",
.....
]
let nsData: NSData?
do {
nsData = try NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions(rawValue:0))
} catch _ {
nsData = nil
}
let defaultConfigObject = NSURLSessionConfiguration.defaultSessionConfiguration()
let defaultSession = NSURLSession(configuration: defaultConfigObject, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let url = NSURL(string: "http:...")!
let urlRequest = NSMutableURLRequest(URL: url)
urlRequest.HTTPMethod = "POST" …Run Code Online (Sandbox Code Playgroud) 可以在协议中声明嵌套类型,如下所示:
protocol Nested {
class NameOfClass {
var property: String { get set }
}
}
Run Code Online (Sandbox Code Playgroud)
Xcode说"Type not allowed here",所以,如果我想创建一个需要嵌套类型的协议,这是不可能的,或者我可以用其他方式做到这一点?
我收到一个错误“Type 'PlayButtonModifier' does not conform to protocol 'ViewModifier' ”,我不明白为什么,更重要的是 - 如何正确地做。
我只是尝试创建一个ViewModifierfor an Image,以便我可以.resizable()在它上面使用例如,它仅在Image
在ViewModifier协议中,有一个TypealiasforContent定义。我天真的想法是这应该有效:
struct PlayButtonModifier: ViewModifier {
typealias Content = Image
func body(content: Content) -> some View {
content
}
}
Run Code Online (Sandbox Code Playgroud)
嗯,不。太容易了。结构的隐式类型别名也会发生同样的事情:
struct PlayButtonModifier: ViewModifier {
func body(content: Image) -> some View {
content
}
}
Run Code Online (Sandbox Code Playgroud)
同样的错误。
这里有什么问题?怎么会是正确的?
给定没有任何关联类型的协议:
protocol SomeProtocol
{
var someProperty: Int { get }
}
Run Code Online (Sandbox Code Playgroud)
这两个函数在实践中有什么区别(意思不是"一个是通用的而另一个不是")?它们是否生成不同的代码,它们具有不同的运行时特征吗?当一个或多个协议变得非常重要时,这些差异是否会发生变化?(因为编译器可能内联这样的东西)
func generic<T: SomeProtocol>(some: T) -> Int
{
return some.someProperty
}
func nonGeneric(some: SomeProtocol) -> Int
{
return some.someProperty
}
Run Code Online (Sandbox Code Playgroud)
我主要询问编译器的不同之处,我理解两者的语言级含义.基本上,确实nonGeneric意味着一个恒定的代码大小但速度较慢的动态调度,而不是generic每个类型传递的代码大小增加,但是使用快速静态调度?
对于实现协议的人,如何使协议方法显示为已弃用?我尝试使用@available如下所示,但在实现协议方法时Xcode中没有显示警告.
protocol TestDelegate {
@available(*, deprecated, message: "Don't use this anymore")
func myMethod() -> Bool
}
extension ViewController: TestDelegate {
func myMethod() -> Bool {
return true
}
}
Run Code Online (Sandbox Code Playgroud) 在UIViewController(rolePageController)中,我配置另一个UIViewController(drawerController)并从角色页面传递2个UIViews,该页面将成为drawerController配置的一部分.一旦drawerController尝试从rolePageController访问IBOutlet视图,它就会崩溃EXC_BAD_ACCESS(代码= EXC_I386_GPFLT).
在第一个VC(rolePageController)中,这里是IBOutlets:
@IBOutlet var rolePageDrawerView: UIView!
@IBOutlet var rolePageContentView: UIView!
Run Code Online (Sandbox Code Playgroud)
在rolePageController.viewDidLoad()中,我调用了抽屉控件.configureDrawer(...):
override func viewDidLoad() {
super.viewDidLoad()
//other stuff happens here
let drawerController = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "drawerController") as! DrawerViewController
drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)
//other stuff here
}
Run Code Online (Sandbox Code Playgroud)
DrawerViewController协议定义为:
protocol DrawerViewController where Self: UIViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
Run Code Online (Sandbox Code Playgroud)
这是configureDrawer(...)func的代码:
private var drawerParentView: UIView!
private var overlaidByDrawerView: UIView!
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView) {
self.drawerParentView = drawerContainerView
self.overlaidByDrawerView = overlaidView
}
Run Code Online (Sandbox Code Playgroud)
在调试器中注意到,调用的drawerController实例与接收调用的self实例不匹配.这是将被调用的实例的地址:
这是我进入呼叫时实例的地址:
当我进入呼叫时,呼叫前抽屉控制器的地址不是自己的地址.这绝不应该发生.
我创建了一个简化的项目,通过https://github.com/ksoftllc/DynamicStackBufferOverflow重现崩溃. …
我正在开发一个应用程序,需要在view和containerView之间传递数据.我需要从两个视图发送数据和接收数据.
让我解释一下:
我可以通过协议更改Label Master(触摸容器按钮),但我无法更改标签容器(触摸主按钮).发生的事情是Master通过以下方式与容器连接.但是没有跟随Container链接到Master.
我试图添加但是segue,但它有效.
主视图控制器:
import UIKit
protocol MasterToContainer {
func changeLabel(text:String)
}
class Master: UIViewController, ContainerToMaster {
@IBOutlet var containerView: UIView!
var masterToContainer:MasterToContainer?
@IBOutlet var labelMaster: UILabel!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "containerViewSegue" {
let view = segue.destinationViewController as? Container
view!.containerToMaster = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func button_Container(sender: AnyObject) {
masterToContainer?.changeLabel("Nice! It's work!")
}
func changeLabel(text: String) {
labelMaster.text = text …Run Code Online (Sandbox Code Playgroud)