标签: swift-protocols

使类型的属性,并符合Swift中的协议

我想创建一个特定类型的属性,并且符合协议,我会在Objective-C中完成这样的:

@property (nonatomic) UIViewController<CustomProtocol> *controller;
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是指定可以使用类型为UIViewController的对象设置属性,该对象也符合CustomProtocol,以便清楚基类是什么.我知道我可能只是使用一个短类存根来获得相同的结果,即

class CustomViewController : UIViewController, CustomProtocol {}
Run Code Online (Sandbox Code Playgroud)

但这似乎不是最干净的方法.

uiviewcontroller swift swift-protocols

11
推荐指数
2
解决办法
2071
查看次数

Downcast Generic AnyObject to Protocol Associated Type Self.Model

我正在开发一个Restofire库,我想在其中保留一个配置对象.我想在配置对象中有一个ResponseSerializer,但事情是ResponseSerializer是一个通用的.

public struct Configuration<M> {

    /// The Default `Configuration`. 
    static let defaultConfiguration = Configuration<AnyObject>()

    /// The base URL. `nil` by default.
    public var baseURL: String!

    /// The `ResponseSerializer`
    public var responseSerializer: ResponseSerializer<M, NSError> = AlamofireUtils.JSONResponseSerializer()

    /// The logging, if enabled prints the debug textual representation of the 
    /// request when the response is recieved. `false` by default.
    public var logging: Bool = false

}
Run Code Online (Sandbox Code Playgroud)

我用baseUrl设置了defaultConfiguration Configuration.defaultConfiguration.baseUrl = "http://httpbin.org/"

我有一个带有associatedType要求的协议,它使用defaultConfiguration作为默认实现.但我需要将通用AnyObject更改为associatedType模型,以便配置对象的responseSerializer返回类型Model.

public protocol Configurable {

    associatedtype Model

    /// The Restofire …
Run Code Online (Sandbox Code Playgroud)

generics ios swift swift-protocols

11
推荐指数
1
解决办法
480
查看次数

Swift 3转换错误/ NSError

在尝试迁移到Swift 3时(在包含大约一半/半swift/objective-c代码的项目中),我遇到了一个问题.我们在objective-c中声明这个特定的协议,如下所示:

@protocol AProtocolDeclaration <NSObject>

- (void)someEventHappened:(nullable NSError *)error;

@end
Run Code Online (Sandbox Code Playgroud)

Swift编译器为上面的协议声明生成以下内容:

public protocol AProtocolDeclaration : NSObjectProtocol {

    public func someEventHappened(_ error: Error?)
}    
Run Code Online (Sandbox Code Playgroud)

当在a中实现协议concrete class (in swift)并尝试定义生成的方法时,我会继续得到类似的错误:无法转换Error to NSError.我不知道如何解决这个错误.有人可以建议吗?

objective-c nserror ios swift-protocols swift3

11
推荐指数
1
解决办法
7961
查看次数

KV在Swift 4中保留一个协议

我正在努力在Swift 4中使用新的强类型KVO语法来观察仅通过协议可见的属性:

import Cocoa

@objc protocol Observable: class {
    var bar: Int { get }
}

@objc class Foo: NSObject, Observable {
    @objc dynamic var bar = 42
}

let implementation = Foo()

let observable: Observable = implementation

let observation = observable.observe(\.bar, options: .new) { _, change in
    guard let newValue = change.newValue else { return }

    print(newValue)
}

implementation.bar = 50
Run Code Online (Sandbox Code Playgroud)
error: value of type 'Observable' has no member 'observe'
let observation = observable.observe(\.bar, options: .new) { _, change …
Run Code Online (Sandbox Code Playgroud)

key-value-observing swift-protocols swift4

11
推荐指数
1
解决办法
893
查看次数

在swift单元测试中以一种快速的方式模拟静态类方法?

我是一名经验丰富的Objective-c程序员,但我不能对Swift说同样的话,我很难在不使用像OCMock这样的框架的情况下在swift中测试一个类.

问题:我正在将Firebase集成到一个混合的Objective-C/Swift项目中,我需要根据应用程序的构建配置对其进行配置.

我为此编写了一个Swift类(将由obj-c app委托使用),但是由于firebase框架是通过静态类方法配置的FIRApp.configure(with: FIROptions),所以我需要以某种方式模拟这个方法以进行单元测试它.

我的代码,没有任何处理依赖注入,看起来像这样:

@objc class FirebaseConfigurator: NSObject{

    func configureFirebase(){

        let config = configManager.buildConfiguration

        var optionsPlistBaseName = getPlistName()

        let optionsFile = Bundle.main.path(forResource: optionsPlistBaseName, ofType: "plist")

        guard let opts = FIROptions(contentsOfFile: optionsFile) else{
            assert(false, "fatal: unable to load \(optionsFile)")
            return
        }

        FIRApp.configure(with: opts)

    }

    func getPlistName() -> String{
        // retrieves correct plist name and returns it
    }

}
Run Code Online (Sandbox Code Playgroud)

我做了一些研究,但到目前为止我没有发现任何适合我的解决方案,但我想到的是以下其中一项:

  • 我可以传递一个默认的函数FIRApp.configure(with:)但是我应该从objective-c执行此操作并且函数也接受一个参数,我正在努力学习语法
  • 我可以在FIRApp周围使用包装器,但我想避免它,除非唯一可行的清洁解决方案.
  • 我可以继续使用协议并进行依赖性反转,但是作为静态的方法我再次遇到语法,我找不到一个简单的方法来使用静态方法对模拟类进行DI.

作为参考(个人和可能需要它的人),这些是我认为有用的一些资源,我将继续挖掘:

同时,每一个帮助都会非常感激.

作为旁注,有很多方法可以解决这个问题而不用嘲笑静态类方法,但我的目标是找到一种嘲弄它的方法,以便在测试更复杂时更好地理解最佳实践的情况.

unit-testing dependency-injection xctest swift swift-protocols

10
推荐指数
1
解决办法
1909
查看次数

不理解“成员 '&lt;func&gt;' 不能用于类型 'any &lt;type&gt;' 的值;请考虑使用通用约束”错误

我无法完全掌握协议和泛型的问题。

在下面的代码中,用 ERROR HERE 注释标记,我收到以下错误:

成员“protocolMethod”不能用于“any Protocol1”类型的值;考虑使用通用约束来代替

我认为它抱怨主要是因为参数的类型item至少在某种程度上未解决?不幸的是,我发现这个建议没有帮助,因为我不知道通用约束在这里有何帮助(至少就我对它们的理解而言)。

老实说,我觉得我可能对 Swift 要求太多了。

有人可能会看到问题是什么或有尝试解决此问题的建议吗?

添加于 12/26/22 - 作为进一步的背景,导致错误出现的原因是将参数添加itemprotocolMethod协议上的方法中,这几乎表明它是问题的核心。

protocol Protocol1
{
    associatedtype DataItem
    func protocolMethod(item : DataItem)
}

protocol Protocol2 {
    associatedtype AType1: Hashable
    //...
}

class Class1<Type1: Protocol2>: NSObject
{
    
    typealias Item = Type1.AType1
    
    var delegate : (any Protocol1)?
     
    private func method1(item: Item)
    {
        delegate?.protocolMethod(item : item)  //ERROR HERE
    }
}

Run Code Online (Sandbox Code Playgroud)

(使用最新的Xcode)

generics swift swift-protocols

10
推荐指数
1
解决办法
5444
查看次数

从另一个框架扩展Swift协议时出现意外行为(Restofire)

我有两个框架

首先 - Restofire.它有一个协议ResponseSerializer与扩展.

public protocol ResponseSerializable {

    /// The type of object returned in response.
    associatedtype Model

    /// The `Alamofire.ResponseSerializer`.
    var responseSerializer: ResponseSerializer<Model, NSError> { get }

}

extension ResponseSerializable {

    /// `CustomJSONResponseSerializer`
    public var responseSerializer: ResponseSerializer<Model, NSError> {
        return AlamofireUtils.JSONResponseSerializer()
    }

}
Run Code Online (Sandbox Code Playgroud)

第二 - Restofire-Gloss.它具有对Restofire框架中符合Decodable的模型的协议的扩展.

public extension ResponseSerializable where Model: Decodable {

    /// `GLOSSResponseSerializer`
    public var responseSerializer: ResponseSerializer<Model, NSError> {
        return GlossUtils.GLOSSResponseSerializer()
    }

}

public extension ResponseSerializable where Model: CollectionType, Model.Generator.Element: Decodable {

    /// `GLOSSResponseSerializer`
    public …
Run Code Online (Sandbox Code Playgroud)

ios swift swift-protocols swift2

9
推荐指数
1
解决办法
230
查看次数

使用swift 3使用UIViewControllerAnimatedTransitioning时遇到问题

我正在尝试按照教程构建自定义转换.一旦我得到了涉及UIViewControllerAnimatedTransitioning的部件的自定义,我就开始出错了.(我对于斯威夫特来说还是新手,所以到目前为止,我们需要付出很多努力才能展现出来).

我一直得到2个错误.1 -

无法指定'CircleTransitionAnimator'类型的值来键入'CAAnimationDelegate?'

2 -

方法不会覆盖其超类中的任何方法

我猜这个问题与UIViewControllerAnimatedTransitioning有关

class CircleTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.5
}

weak var transitionContext: UIViewControllerContextTransitioning?

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    self.transitionContext = transitionContext

    var containerView = transitionContext.containerView()
    var fromViewController = transitionContext.viewController(forKey: UITransitionContextFromViewControllerKey) as! ViewController
    var toViewController = transitionContext.viewController(forKey: UITransitionContextToViewControllerKey) as! ViewController
    var button = fromViewController.button

    containerView.addSubview(toViewController.view)

    var circleMaskPathInitial = UIBezierPath(ovalIn: (button?.frame)!)
    var extremePoint = CGPoint(x: (button?.center.x)! - 0, y: (button?.center.y)! - toViewController.view.bounds.height)
    var radius = sqrt((extremePoint.x*extremePoint.x) …
Run Code Online (Sandbox Code Playgroud)

swift swift-protocols

9
推荐指数
1
解决办法
3892
查看次数

`ExpressibleByArrayLiteral`符合类及其超类=>"<superclass>不可转换为<subclass>"

我希望能够使用数组文字实例化一个子类,这里MyLabel是一个子类,它是一个子类UILabel.我在我的框架ViewComposer中使用它,它允许使用枚举视图的数组来创建UIViews,如下所示:

let label: UILabel = [.text("Hello World"), .textColor(.red)]
Run Code Online (Sandbox Code Playgroud)

在这个问题中,我大大简化了用例,而是允许编写:

let vanilla: UILabel = [1, 2, 3, 4]  // works!
print(vanilla.text!) // prints: "Sum: 10"
Run Code Online (Sandbox Code Playgroud)

我想要做的是使用相同的ExpressibleByArrayLiteral语法,但使用的是被UILabel调用的子类MyLabel.但是当我尝试时,编译器会阻止我:

let custom: MyLabel = [1, 2, 3, 4] // Compilation error: "Could not cast value of type 'UILabel' to 'MyLabel'"
Run Code Online (Sandbox Code Playgroud)

UILabel由于符合Makeable以下自定义协议,使用数组文字的实例化可行.

是否有可能使编译器理解我指的是子类的数组文字初始值设定项MyLabel而不是它的超类UILabel

以下代码可能没有任何逻辑意义,但它是一个最小的例子,隐藏了我真正想要的东西:

// This protocol has been REALLY simplified, in fact …
Run Code Online (Sandbox Code Playgroud)

uiview ios swift swift-protocols swift3

9
推荐指数
2
解决办法
433
查看次数

为什么“即使有不同的条件界限,也不能有多个一致性”?

我希望 Swift 使我能够在where块中为具有指定条件的类型创建扩展。我想象我可以使用依赖于具体泛型类型值 ( T) 的不同扩展来扩展相同的泛型类型。但不是。以下示例演示了我的问题:

protocol P {    
    associatedtype Prop 
    var property: Prop { get }
}

enum E<T: P> {
   case single(T)
   case double(T)
}

extension E: P where T.Prop == Int {
   var property: Int {
      switch self {
      case .single(let o): return o.property
      case .double(let o): return o.property * 2
      }
   }
}

extension E: P where T.Prop == String {
   var property: String {
      switch self {
      case .single(let o): return o.property …
Run Code Online (Sandbox Code Playgroud)

generics swift swift-extensions swift-protocols

9
推荐指数
2
解决办法
1442
查看次数