本文介绍了如何提供UIPageViewControllerDataSource的默认实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我假设此问题的答案通常会解决Objective-C协议的问题,但这是我遇到的第一个此类问题。
我希望在实现UIPageViewControllerDataSourceWithConnections.时使用这些方法import UIKit
protocol UIPageViewControllerDataSourceWithConnections: UIPageViewControllerDataSource {
var connectedViewControllers: [UIViewController] {get}
}
extension UIPageViewControllerDataSourceWithConnections {
func pageViewController(pageViewController: UIPageViewController,
viewControllerBeforeViewController viewController: UIViewController
) -> UIViewController? {return connectedViewController(
current: viewController,
adjustIndex: -
)}
func pageViewController(pageViewController: UIPageViewController,
viewControllerAfterViewController viewController: UIViewController
) -> UIViewController? {return connectedViewController(
current: viewController,
adjustIndex: +
)}
private func connectedViewController(
current viewController: UIViewController,
adjustIndex: (Int, Int) -> Int
) -> UIViewController? {
let requestedIndex = adjustIndex(connectedViewControllers.indexOf(viewController)!, 1)
return connectedViewControllers.indices.contains(requestedIndex) ?
connectedViewControllers[requestedIndex] : nil
}
func presentationCountForPageViewController(pageViewController: UIPageViewController)
-> Int {return connectedViewControllers.count}
func presentationIndexForPageViewController(pageViewController: UIPageViewController)
-> Int {
return connectedViewControllers.indexOf(pageViewController.viewControllers!.first!)!
}
}
但是,这不会编译。我必须实施这些胡言乱语才能让事情运转起来。你能告诉我为什么吗?是否有代码较少的解决方案可用?
// connectedViewControllers is defined elsewhere in InstructionsPageViewController.
extension InstructionsPageViewController: UIPageViewControllerDataSourceWithConnections {
// (self as UIPageViewControllerDataSourceWithConnections) doesn't work.
// Workaround: use a different method name in the protocol
func pageViewController(pageViewController: UIPageViewController,
viewControllerBeforeViewController viewController: UIViewController
) -> UIViewController? {
return 😾pageViewController(pageViewController,
viewControllerBeforeViewController: viewController
)
}
func pageViewController(pageViewController: UIPageViewController,
viewControllerAfterViewController viewController: UIViewController
) -> UIViewController? {
return 😾pageViewController(pageViewController,
viewControllerAfterViewController: viewController
)
}
// (self as UIPageViewControllerDataSourceWithConnections)
// works for the optional methods.
func presentationCountForPageViewController(pageViewController: UIPageViewController)
-> Int {
return (self as UIPageViewControllerDataSourceWithConnections)
.presentationCountForPageViewController(pageViewController)
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController)
-> Int {
return (self as UIPageViewControllerDataSourceWithConnections)
.presentationIndexForPageViewController(pageViewController)
}
}
推荐答案
当您遇到这样的问题时,如果您想知道SWIFT语言本身的限制,将其简化为问题的更简单版本会有所帮助。
首先,让我们问一下:是否可以扩展协议采用协议,将该协议要求的默认实现注入到最终采用类中?是的,它是合法的;此代码是合法的:protocol Speaker {
func speak()
}
protocol DefaultSpeaker : Speaker {
}
extension DefaultSpeaker {
func speak() {
print("howdy")
}
}
class Adopter : DefaultSpeaker {
}
好的,那么您的代码还能做什么呢?它还注入了一个额外的需求(实例变量)。这合法吗?是的,是这样的。此代码也是合法的:protocol Speaker {
func speak()
}
protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak() {
print(self.whatToSay)
}
}
class Adopter : DefaultSpeaker {
var whatToSay = "howdy"
}
那么斯威夫特不喜欢的是什么呢?我们在这里没有做什么,你的代码做了什么?事实是,原始协议是@objc
。如果我们将protocol Speaker
更改为@objc protocol Speaker
(并进行所有其他必要的更改),代码将停止编译:@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak() {
print(self.whatToSay)
}
}
class Adopter : NSObject, DefaultSpeaker { // ERROR
var whatToSay = "howdy"
}
我猜这是因为Objective-C对协议扩展一无所知。因为我们所需的协议方法的实现依赖于协议扩展,所以从Objective-C的观点来看,我们不能以满足编译器的要求的方式采用该协议。我们必须在类中实现需求,Objective-C可以看到我们的实现(这正是您的解决方案所做的):@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak2() {
print(self.whatToSay)
}
}
class Adopter : NSObject, DefaultSpeaker {
var whatToSay = "howdy"
func speak() {
self.speak2()
}
}
因此,我得出结论,您的解决方案是最好的。
您所做的实际上更像这样,我们在Adadter类上使用一个扩展来注入"钩子"方法:
@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak2() {
print(self.whatToSay)
}
}
class Adopter : NSObject {
}
extension Adopter : DefaultSpeaker {
var whatToSay : String { return "howdy" }
func speak() {
self.speak2()
}
}
这是可行,因为最后extension
是客观类可以看到的东西:对象-C类的扩展实际上是一个范畴,目标-C可以理解。 这篇关于如何提供UIPageViewControllerDataSource的默认实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!