标签: swift-protocols

Swift 协议:隐藏一些属性

我想trimmedTextUITextViewand创建一个属性UITextField。这是我所做的:

protocol TrimmedTextSupporting: class {
  var _text: String? { get }
  var trimmedText: String { get }
}

extension TrimmedTextSupporting {
  var trimmedText: String {
    let text = self._text ?? ""
    return text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
  }
}

extension UITextField: TrimmedTextSupporting {

  var _text: String? {
    return self.text
  }
}

extension UITextView: TrimmedTextSupporting {

  var _text: String? {
    return self.text
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要_text财产,因为text被声明为String?inUITextField和 as String!inUITextView (whyyyy?!>_<)。现在我想隐藏这个属性以避免混淆 API。 …

swift swift-protocols

5
推荐指数
1
解决办法
2855
查看次数

扩展符合协议的类?

如何对实现协议的类进行扩展?

类似的东西:

protocol proto {
    func hey()
}
Run Code Online (Sandbox Code Playgroud)

以及符合以下条件的类proto

Class MyClass: UIViewController, proto {
     func hey() {
         print("Hey!")
     }
}
Run Code Online (Sandbox Code Playgroud)

然后是该类的扩展,如下所示:

extension UIViewController where Self:proto {
     func test() {
         print("I'm extended!")
     }
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以打电话self.test()MyClass

谢谢。

ios swift swift-protocols

5
推荐指数
1
解决办法
903
查看次数

具有相同关联类型名称的协议

如果我有两个协议,其关联类型恰好相同,例如

protocol Read {
    associatedtype Element
    func read() -> Element
}
protocol Write {
    associatedtype Element
    func write(a: Element)
}
Run Code Online (Sandbox Code Playgroud)

然后我想要一个类来读取整数并将字符串写入:

class ReadWrite: Read, Write {
    func read() -> Int {
        return 5
    }
    func write(a: String) {
        print("writing \(a)")
    }
}
Run Code Online (Sandbox Code Playgroud)

但编译器抱怨并建议更改StringInt. 理想情况下,应该推断类型,或者至少在我显式声明时编译

associatedtype Read.Element = Int
associatedtype Write.Element = String
Run Code Online (Sandbox Code Playgroud)

之内ReadWrite。有解决办法吗?

更新

受此问题启发的解决方法是创建两个辅助协议

protocol ReadInt: Read {
    associatedtype Element = Int
}
protocol WriteString: Write {
    associatedtype Element = String
} …
Run Code Online (Sandbox Code Playgroud)

associated-types swift swift-protocols

5
推荐指数
1
解决办法
1476
查看次数

是否可以将通用协议传递给构造函数以在 Swift 3 中进行适当的依赖注入?

我正在尝试使用泛型在 Swift 3 中完成面向协议的编程。这还不完全支持吗?我将在下面向您展示我想做但不会编译的内容。我在这里错过了什么吗?我的目标是能够使用面向协议的编程来执行依赖注入,目的是在我的单元测试中轻松模拟这些结构。

protocol ZombieServiceProtocol {

    func fetchZombies()
    var zombieRepository: RepositoryProtocol<Zombie> { get set }
}

struct ZombieService: ZombieServiceProtocol {

    var zombieRepository: RepositoryProtocol<Zombie>

    init(zombieRepository: RepositoryProtocol<Zombie>) {
        self.zombieRepository = zombieRepository
    }

    func fetchZombies() {
        self.zombieRepository.deleteAll()
        self.createFakeZombies()
    }

    private func createFakeZombies() {
        for index in 1...100 {
            let zombie = Zombie(id: index, name: "Zombie \(index)")
            self.zombieRepository.insert(zombie)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Zombie 类如下所示:

public struct Zombie: Persistable {

    var id: Int
    let name: String?
    init(id: Int, name: String?) {
            self.id = id
            self.name …
Run Code Online (Sandbox Code Playgroud)

generics dependency-injection swift swift-protocols

5
推荐指数
1
解决办法
936
查看次数

使用通用枚举和通用协议进行快速类型擦除

我不得不在 Swift 中使用类型擦除几次,但它总是涉及通用协议。在这种情况下,它涉及通用枚举通用协议,我被难住了。

这是我的通用枚举和通用协议以及必要的扩展:

enum UIState<T> {
    case Loading
    case Success([T])
    case Failure(ErrorType)
}

protocol ModelsDelegate: class {
    associatedtype Model
    var state: UIState<[Model]> { get set }
}

extension ModelsDelegate {

    func getNewState(state: UIState<[Model]>) -> UIState<[Model]> {
        return state
    }

    func setNewState(models: UIState<[Model]>) {
        state = models
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的类型擦除泛型类:

class AnyModelsDelegate<T>: ModelsDelegate {
    var state: UIState<[T]> {

        get { return _getNewState(UIState<[T]>) }  // Error #1
        set { _setNewState(newValue) }
    }

    private let _getNewState: ((UIState<[T]>) -> UIState<[T]>)
    private …
Run Code Online (Sandbox Code Playgroud)

generics ios swift swift-protocols swift2

5
推荐指数
1
解决办法
1452
查看次数

在Swift协议上引用静态变量的正确方法是什么?

假设下面定义了一个协议:

protocol Identifiable {
  static var identifier: String { get }
}
extension Identifiable {
  static var identifier: String { return "Default Id" }
}
Run Code Online (Sandbox Code Playgroud)

引用静态变量的最佳方法是什么?下面的示例说明了两种访问变量的方法。有什么区别,type(of:)更好吗?

func work<I: Identifiable>(on identifiable: I) {
  let identifier: String = I.identifier
  print("from Protocol: \(identifier)")

  let identiferFromType: String = type(of: identifiable).identifier
  print("using type(of:): \(identiferFromType)")
}

struct Thing: Identifiable {
  static var identifier: String { return "Thing" }
}

work(on: Thing())
Run Code Online (Sandbox Code Playgroud)

generics swift swift-protocols

5
推荐指数
1
解决办法
1224
查看次数

检索实体名称时崩溃?

当我的应用程序第一次启动时,我做了一些第一次设置配置,它使用 CoreData API 和来自 JSON 文档的数据为我的 SQLLite 数据库做种。

为此,我首先从核心数据堆栈获取对托管对象上下文的引用,然后调用执行 JSON 配置的方法。然后我打电话:

....(JSON conversion)....

context.perform {
 _ = Exercise.insert(into: context, name: exerciseName, category: categoryNumber, equipment: equipment, skill: "", primaryMuscle: primaryMuscle, otherMuscles: otherMuscles, info: exerciseDescription, image1: exerciseImage1, image2: exerciseImage2)
   }
Run Code Online (Sandbox Code Playgroud)

在我循环遍历 JSON 对象时的每次迭代中,它都会保留每个对象。

插入对象的方法是这样的:

public static func insert(into context: NSManagedObjectContext, name: String, category: Int16, equipment: String?, skill: String?, primaryMuscle: String?, otherMuscles: String?, info: String?, image1: String?, image2: String?) -> Exercise {
    let exercise: Exercise = context.insertObject()
    exercise.name = name
    exercise.category = category …
Run Code Online (Sandbox Code Playgroud)

sqlite xcode core-data nsmanagedobject swift-protocols

5
推荐指数
1
解决办法
777
查看次数

Swift 扩展和单元测试

我有一些 UT 的问题,我正在尝试快速编写

我有一个带有“做事”扩展名的协议:

protocol MyProtocol: class
{
    var myVar: SomeClass { get }

    func doStuff(identifier: String) -> Bool
}

extension MyProtocol
{
    func doStuff(identifier: String) -> Bool {
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是一个实现我的协议的类

final class MyClass: MyProtocol {

}
Run Code Online (Sandbox Code Playgroud)

这个类有一个扩展,它实现了另一个协议,它有一个我应该测试的方法

public protocol MyOtherProtocol: class {
    func methodToTest() -> Bool
}

extension MyClass: MyOtherProtocol {
    public func methodToTest() {
        if doStuff() {
            return doSomething()
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

这个设置有没有办法模拟 doStuff 方法?

unit-testing swift swift-protocols

5
推荐指数
1
解决办法
2787
查看次数

协议扩展初始化器强制调用 self.init

我只是在阅读有关协议初始值设定项要求的 Apple Swift 4 文档并在协议扩展中提供默认实现。

import UIKit
protocol Protocol {
    init()
}
extension Protocol {
    init() {
        print("SDf")
        self.init() // Line 1
                    // Compiler error occured if this is omitted 
                    //"'self.init' isn't called on all paths before returning from initializer"
    }
}

struct Structure: Protocol {
    init(string: String) {

    }
}

Structure()      // Line 2
Run Code Online (Sandbox Code Playgroud)

现在如您所见,执行将进入循环,因为默认情况下该结构没有实现 for init(),因此将调用提供的协议 init 并再次调用自身,因此进入无限循环.

现在,知道了这一点,如果我删除第 1 行,编译器就会给出错误。

Q. 为什么强制我self.init()在1号线使用,如何摆脱这种情况?

swift swift-protocols

5
推荐指数
1
解决办法
2073
查看次数

调度到 Swift 协议扩展

为什么以下代码在#2 处打印“BaseP”?

protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }

class C: SubP {}
let subP1: SubP = C()
subP1.foo()   //  #1 prints "SubP", fine.

class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo()   //  #2 prints "BaseP". why?

    
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,我们调用foo()静态类型为 的SubP引用,引用具有动态类型的对象,该对象是符合 的类SubP。即使它是静态调度,我认为它仍然应该调用SubP.foo(). 为什么在#2 处调用基本协议实现?

另外,为什么继承 from …

swift swift-protocols

5
推荐指数
1
解决办法
51
查看次数