Unable to implement computed property override on UIViewController - swift

When trying to implement this:
extension UIViewController {
public var presentedViewController: UIViewController? {
return UIViewController()
}
}
I'm receiving the following error:
.../ExampleApp/ExampleAppTests/SpecExtensions.swift:41:59: Getter for 'presentedViewController' with Objective-C selector 'presentedViewController' conflicts with method 'presentedViewController()' with the same Objective-C selector
I'm using the same selector that UIViewController.h defines:
public var presentedViewController: UIViewController? { get }
Is the error misleading or am I just overlooking something? I've tried it with and without override, public, as a method, etc. No luck. However, I am able to override it if it's on a subclass of UIViewController, but not UIViewController itself.

The problem is that you have it in an extension. You can't override methods that were defined on a class from an extension. Basically an extension is not a sub-class, trying to redefine methods that exist on a class by implementing a new version in an extension will fail.
Note that this works:
class ViewController: UIViewController {
override var presentedViewController: UIViewController? {
return UIViewController()
}
}

Related

Using protocol's associated type in generic functions

I'm trying to write a simple MVP pattern to follow in my app, so I've written two porotocols to define View Controller and Presenters:
protocol PresenterType: class {
associatedtype ViewController: ViewControllerType
var viewController: ViewController? { get set }
func bind(viewController: ViewController?)
}
protocol ViewControllerType: class {
associatedtype Presenter: PresenterType
var presenter: Presenter { get }
init(presenter: Presenter)
}
After having those defined I started writing some RootViewController and RootViewPresenter. The latter looks like:
protocol RootViewControllerType: ViewControllerType {
}
final class RootPresenter<VC: RootViewControllerType>: PresenterType {
weak var viewController: VC?
func bind(viewController: VC?) {
self.viewController = viewController
}
}
Up to this point everything complies and is fine, but when I start implementing View Controller like this:
protocol RootPresenterType: PresenterType {
}
final class RootViewController<P: RootPresenterType>: UIViewController, ViewControllerType {
let presenter: P
init(presenter: Presenter) {
self.presenter = presenter
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
presenter.bind(viewController: self)
}
}
Immediately I get the following error message:
Cannot convert value of type 'RootViewController' to expected argument type '_?'
I know that protocols with associated types can introduce some limitations, but this example is pretty straightforward and I can't make it work. Is it possible to achieve something that I want, or do I have to look for some other, less Swifty pattern?
I don't think what you're trying to achieve is possible due to the circular dependency between the respective associated types of the PresenterType and ViewControllerType protocols.
Consider for a moment if the suspect code above did compile ... how would you go about instantiating either the RootPresenter or RootViewController classes? Because both depend on one another, you'll end up with errors like the following:
As you can see, the compiler can't fully resolve the generic parameters due to the associated types.
I think your best bet is to remove the associated type from one or both of the protocols. For example, removing the associated type from the PresenterType protocol and updating the RootPresenter class breaks the circular dependency and allows your code to compile normally.
protocol PresenterType: class {
var viewController: UIViewController? { get set }
func bind(viewController: UIViewController?)
}
final class RootPresenter: PresenterType {
weak var viewController: UIViewController?
func bind(viewController: UIViewController?) {
self.viewController = viewController
}
}

ViewController does not conform to protocol xyzDelegate

// QuizPopUpViewController.swift
#objc protocol QuizPopUpViewControllerDelegate {
func ApplyNowToSendBack()
}
class QuizPopUpViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
weak var delegate: QuizPopUpViewControllerDelegate?
}
// giving event from here
if isError == false {
self.delegate?.ApplyNowToSendBack() // delegate method
}
}
// Another Viewcontroller
class ShortlistViewController: ParentViewController , QuizPopUpViewControllerDelegate {
}
When i add QuizPopUpViewControllerDelegate to ShortlistViewController, i get the following error:
Type "ShortlistviewController" does not conform to protocol QuizPopUpViewControllerDelegate
The problem is exactly what the error description is suggesting. You need to make your class conforming on QuizPopUpViewControllerDelegate delegate.
To do so, you need to declare the function, what is in QuizPopUpViewControllerDelegate.
// Another Viewcontroller
class ShortlistViewController: ParentViewController , QuizPopUpViewControllerDelegate {
func ApplyNowToSendBack() {
// do something with the callback.
}
}
To avoid asking such questions in the future, i would recommend to read more about the delegate pattern in Swift.

Delegation on a class in Swift

I have a delegation/initialization problem I can't seem to solve. Basically I have a storyboard with a few View controllers. Inside the storyboard there is this "View controller" which consists of a UITableview that I have connected with a DeviceListViewController class so that it populates the information. In here I have declared the following protocol:
protocol DeviceListViewControllerDelegate: UIAlertViewDelegate {
var connectionMode:ConnectionMode { get }
func connectPeripheral(peripheral:CBPeripheral, mode:ConnectionMode)
func stopScan()
func startScan()
}
and inside the class itself I have a init method like this (which is probably wrong but I didn't know what else I could do at this point):
convenience init(aDelegate: DeviceListViewControllerDelegate) {
self.init()
self.delegate = aDelegate
}
Then there is this second class that is not attached to any view controller called BLEMainViewController. It should be a singleton handling all the bluetooth actions. This means I should be able to delegate some stuff between DevicelistViewController and BLEMainViewController.
In the BLEMainViewController I have inherited the DeviceListViewControllerDelegate:
class BLEMainViewController: NSObject, DeviceListViewControllerDelegate {
var deviceListViewController:DeviceListViewController!
var delegate: BLEMainViewControllerDelegate?
static let sharedInstance = BLEMainViewController()
}
override init() {
super.init()
// deviceListViewController.delegate = self
deviceListViewController = DeviceListViewController(aDelegate: self)
}
The problem is that BLEMainViewController is not attached to any View Controller (and it shouldn't IMO) but it needs to be initialized as a singleton in order to handle all the BLE actions. Can anyone point me in the right direction (with an example preferably) on how to work around this?
I think you simply used wrong code architecture.
The BLEManager is a shared-instance, you can call it from everywhere, set it properties, and call its methods.
Its can delegate your view-controller with any predefine events you will add to its protocol and provide proper implementation
Here is some code, hope it helps
protocol BLEManagerDelegate{
func bleManagerDidStartScan(manager : BLEManager)
}
class BLEManager: NSObject {
static let sharedInstance = BLEManager()
var delegate: BLEManagerDelegate?
var devices : [AnyObject] = []
func startScan(){
delegate?.bleManagerDidStartScan(self)
//do what ever
}
func stopScan(){
}
}

Altering (refining) delegate type in swift

I have a (swift) class which has a weak pointer to a delegate like this:
import UIKit
#objc public protocol DRSlidingPanelViewControllerDelegate : class {
optional func didSlidePanel(panelHidden : Bool , sender : DRSlidingPanelViewController) -> Void
}
public class DRSlidingPanelViewController: UIViewController {
public weak var delegate : DRSlidingPanelViewControllerDelegate?
///other stuff...
}
Now i make a subclass with another protocol which extends the first, and i want to alter the inherited 'delegate' property
#objc public protocol DRTableViewControllerDelegate : DRSlidingPanelViewControllerDelegate {
optional func someFunction(sender : DRTableViewController) -> Void
}
public class DRTableViewController: DRSlidingPanelViewController {
// public weak var delegate : DRTableViewControllerDelegate?
}
^ this (re)declaration of delegate in the subclass gives me 3 errors when I uncomment it.
Property 'delegate' with type 'DRTableViewControllerDelegate?' (aka 'Optional') cannot override a property with type 'DRSlidingPanelViewControllerDelegate?' (aka 'Optional')
Getter for 'delegate' with Objective-C selector 'delegate' conflicts with getter for 'delegate' from superclass 'DRSlidingPanelViewController' with the same Objective-C selector
Setter for 'delegate' with Objective-C selector 'setDelegate:' conflicts with setter for 'delegate' from superclass 'DRSlidingPanelViewController' with the same Objective-C selector
Now i understand the nature of these errors, and that they are different facets of the one error (attempting to change the 'type' on the delegate pointer.) Can anybody give me a clue how to do this? It obviously can be done, look at how UITableView alters the delegate pointer which it inherits from UIScrollView. In objC I would get a warning which could be silenced with an #dynamic.
Thanks and best regards
edit / addition
Thanks Matt, I do see this previous question, but unfortunately it is closed and I would personally not accept that answer as the definitive answer because it is a compromise.
If I right click on UITableView in xCode and 'jump to definition' I see this
#available(iOS 2.0, *)
public class UITableView : UIScrollView, NSCoding {
public init(frame: CGRect, style: UITableViewStyle) // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain
public init?(coder aDecoder: NSCoder)
public var style: UITableViewStyle { get }
weak public var dataSource: UITableViewDataSource?
**weak public var delegate: UITableViewDelegate?**
//plenty other stuff..
}
So I respectfully submit that there definitely is a way to do this.
I would say that as things stand you can't do it. This is disappointing to say the least. You'll just have to call the delegate variable in the subclass something else.
So, this is legal, but of course it totally fails to meet your requirements:
#objc protocol P1 {
}
#objc protocol P2 : P1 {
}
public class VC1: UIViewController {
weak var delegate : P1?
}
public class VC2: VC1 {
weak var delegate2 : P2?
}
If you really hate the multiplication of storage you can make the delegate2 a computed variable that accesses the inherited delegate:
#objc protocol P1 {
}
#objc protocol P2 : P1 {
}
public class VC1: UIViewController {
weak var delegate : P1?
}
public class VC2: VC1 {
weak var delegate2 : P2? {
set {
super.delegate = newValue
}
get {
return super.delegate as? P2
}
}
}

NSViewController delegate?

I'm new to using delegates in Swift, and I can't seem to figure out how to communicate with my View Controller from a different class. Specifically, I call the custom class's functions from my App Delegate, and then from within that custom class, I call a function within my View Controller. My basic setup, following this question, is:
AppDelegate.swift:
var customClass = customClass()
func applicationDidFinishLaunching(aNotification: NSNotification) {
customClass.customFunction()
}
CustomClass.swift:
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
ViewController.swift:
protocol ViewControllerDelegate: class {
func customFunction(data: AnyObject)
}
class ViewController: NSViewController, ViewControllerDelegate
func customFunction(data: AnyObject){
println("called")
}
}
However, delegate is always nil. I am assuming this is either because the ViewControllerDelegate protocol never gets initialized or because I never set the delegate of the actual NSViewController? I know I'm missing something obvious/straightfoward, however I have yet to see what that is.
Your question is hard to answers because you have completely misunderstood the point of a protocol.
A protocol is a type which is used to define functionality. A class that conforms to this protocol provides the specified functionality, by implementing the required methods.
You can not initialize a protocol.
So if your CustomClass looks like this:
class CustomClass {
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
}
Why do you expect that delegate has suddenly a value?
Of course you have to set delegate to something first. The delegate must set delegate. If you want a ViewController instance to be the delegate, it must assign itself to delegate.
This for instance will work.
protocol ViewControllerDelegate {
func delegateMethod(data: AnyObject) //I renamed this because in
//CustomClass you are trying to call `delegateMethod` on the delegate
}
class CustomClass {
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
}
class ViewController: NSViewController, ViewControllerDelegate
var customClass = CustomClass()
func viewDidLoad(){
customClass.delegate = self
customClass.customFunction()
}
func delegateMethod(data: AnyObject){
println("called")
}
}
Read more about delegation here.