Can I use MCBrowserViewControllerDelegate with GameViewController class instead of ViewController class? - swift

I don't think so. The error I receive states Type 'GameViewController' does not conform to protocol 'MCBrowserViewDelegate' https://developer.apple.com/library/prerelease/ios/documentation/MultipeerConnectivity/Reference/MCBrowserViewController_class/index.html

Assuming that GameViewController is a subclass of UIViewController, you certainly can since MCBrowserViewController is a subclass of UIViewController as well.
The error you are receiving is saying that you are not conforming to the delegate protocols required to use MCBrowserViewController. This means that in order to use a MCBrowserViewController, you first need to add MCBrowserViewDelegate to your class declaration similar to the following.
class GameViewController: UIViewController, MCBrowserViewDelegate {
You will also want to set your GameViewController to be the delegate within viewDidLoad or wherever you create it.
// create the MCBrowserViewController
let browserViewController = MCBrowserViewController(...)
browserViewController.delegate = self
self.presentViewController(browserViewController, animated: true, completion:nil)

Related

swift VAR restriction of types [duplicate]

My app has a protocol for detail view controllers, stating they must have a viewModel property:
protocol DetailViewController: class {
var viewModel: ViewModel? {get set}
}
I also have a few different classes that implement the protocol:
class FormViewController: UITableViewController, DetailViewController {
// ...
}
class MapViewController: UIViewController, DetailViewController {
// ...
}
My master view controller needs a property that can be set to any UIViewController subclass that implements the DetailViewController protocol.
Unfortunately I can't find any documentation on how to do this. In Objective-C it would be trivial:
#property (strong, nonatomic) UIViewController<DetailViewController>;
It appears that there isn't any syntax available in Swift to do this. The closest I've come is to declare a generic in my class definition:
class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
var detailViewController: T?
// ...
}
But then I get an error saying that "Class 'MasterViewController' does not implement its superclass's required members"
This seems like it should be as easy to do in Swift as it is in Objective-C, but I can't find anything anywhere that suggests how I might go about it.
I think you can get there by adding an (empty) extension to UIViewController and then specifying your detailViewController attribute using a composed protocol of the empty extension and your DetailViewController. Like this:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
Now all subclasses of UIViewController satisfy protocol UIViewControllerInject. Then with that, simply:
typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>
class MasterViewController : UITableViewController {
var detailViewController : DetailViewControllerComposed?
// ...
}
But, this is not particularly 'natural'.
=== Edit, Addition ===
Actually, you could make it a bit better if you define your DetailViewController using my suggested UIViewControllerInject. Like such:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
protocol DetailViewController : UIViewControllerInject { /* ... */ }
and now you don't need to explicitly compose something (my DetailViewControllerComposed) and can use DetailViewController? as the type for detailViewController.
As of Swift 4, you can now do this.
Swift 4 implemented SE-0156 (Class and Subtype existentials).
The equivalent of this Objective-C syntax:
#property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Now looks like this in Swift 4:
var detailViewController: UIViewController & DetailViewController
Essentially you get to define one class that the variable conforms to, and N number of protocols it implements. See the linked document for more detailed information.
Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
Then you inherit your view controllers from these view controllers, not the UIKit ones.
This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.

CoreBluetooth set central delegate to another view controller

I have just started translating my app to Swift, I want the CBCentralManager.delegate to be set to another view controller(One that navigation controller pushes onto).
I am trying to do the same with following code:
let viewCont = self.storyboard!.instantiateViewControllerWithIdentifier("mainView")
self.navigationController?.pushViewController(viewCont, animated: true)
manager.delegate = viewCont
The variable manager is an instance of CBCentralManager and setting delegate to viewCont raises following error:
"Cannot assign value of type 'UIViewController' to type 'CBCentralManagerDelegate?'"
The declaration for the view Controller:
class MainViewController: UIViewController, CBCentralManagerDelegate
How can I solve the same?
You need to downcast the view controller you receive from instantiateViewControllerWithIdentifier. Without the downcast, all the compiler knows is that you have a UIViewController
let viewCont = self.storyboard!.instantiateViewControllerWithIdentifier("mainView") as! MainViewController
self.navigationController?.pushViewController(viewCont, animated: true)
manager.delegate = viewCont
Once you have the downcast using as! then the compiler knows that it has a MainViewController and since this class is also a CBCentralManagerDelegate it is happy.

Swift Delegation

I'm having trouble wrapping my head around delegation in Swift. After reading some guides, I was able to set it up delegation between two ViewControllers, but I'm not understanding how it works. In my first view controller, I have a a label that displays what has been entered in the second view controller which contains a text field and a button (that returns to the first view controller). Here is the code for the first view controller:
#IBOutlet weak var labelText: UILabel!
func userDidEnterInformation(info: String) {
labelText.text = info;
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "transition"){
let secondVC: SecondViewController = segue.destinationViewController as! SecondViewController;
secondVC.delegate = self;
}
}
Here's the code for the second view controller:
protocol DataEnteredDelegate{
func userDidEnterInformation(info: String);
}
#IBOutlet weak var userText: UITextField!
var delegate: DataEnteredDelegate? = nil;
#IBAction func buttonPressed(sender: AnyObject) {
let information = userText.text!;
delegate!.userDidEnterInformation(information);
self.navigationController?.popToRootViewControllerAnimated(true);
}
My understanding is that in the text inside the text field gets stored in the information constant, then the userDidEnterInformation method from the protocol is called, with the method being defined inside the first view controller. This method then changes the label inside the first view controller. The thing is, I'm not sure what is happening in the prepareForSegue function. Specifically, I'm not sure what's the purpose of secondVC.delegate = self.
I would appreciate any sort of clarity on delegation.
The diagram is simple but can help you understand what's going on.
FirstViewController must conform to the DataEnteredDelegate protocol you have defined (see Sumit's answer). When using secondVC.delegate = self, you are saying that for the segue transition with the destination being a SecondViewController, the attribute delegate of that SecondViewController instance will be set to this instance of FirstViewController, thus delegating things from SecondViewController to your FirstViewController as made possible by the DataEnteredDelegate protocol.
The protocol you created in second viewcontroller is an Interface. You must implement your first view controller with the DataEnteredDelegate protocol.
class FirstViewController:UIViewController, DataEnteredDelegate{
func userDidEnterInformation(info: String) {
//stub
}
}
If the delegate of the second VC is not set in prepareForSegue() it remains nil. The second VC is then unable to call the first VC.
On a side note, if the delegate is nil your code will crash because delegate! is trying to unwrap an optional binding with the value of nil. It's better to first unwrap the delegate variable:
if let handler = delegate {
handler.userDidEnterInformation(information)
}
Alternatively, you could use Swift's Optional Chaining, calling userDidEnterInformation only if delegate is not nil.
delegate?.userDidEnterInformation(information);
In addition it is recommended to declare the delegate weak, to prevent retain cycles:
weak var delegate: DataEnteredDelegate?
Delegates and Protocols
Do not try to figure out how the dictionary definition of “delegate” fits with the concept of delegation in Swift. It doesn't.
Delegation in Swift is an agreement between two players—a sensing object and a requesting object. The “delegate” is the “requesting object.” Just think “asker” or “requester” every time you see “delegate” and it will make a lot more sense. Here is their agreement...
The Sensing Object (Second View Controller):
I have data from some event that took place. I will publish instructions (a protocol) on how you may access that data. If you want it, you must do three things.
You must declare in your class type that your class abides by my protocol.
You must write the functions that I describe in my protocol. I don't care what those functions do but the function type must match what I publish.
In YOUR code, you must set MY “delegate” (think “asker”) property to point to you. {secondVC.delegate = self} That way I can call one of YOUR functions to deliver the data.
After that, when I get some data, I will call one of the functions in your object that I told you to write. My call to your function will contain the data you are looking for as one of the arguments. {delegate!.userDidEnterInformation(information)} Note: delegate! (asker!) is YOU.
The Delegate (Requesting) Object (First View Controller):
O.K. You've got a deal.

Define a variable which conforms to a protocol and inherits from a class in Swift [duplicate]

My app has a protocol for detail view controllers, stating they must have a viewModel property:
protocol DetailViewController: class {
var viewModel: ViewModel? {get set}
}
I also have a few different classes that implement the protocol:
class FormViewController: UITableViewController, DetailViewController {
// ...
}
class MapViewController: UIViewController, DetailViewController {
// ...
}
My master view controller needs a property that can be set to any UIViewController subclass that implements the DetailViewController protocol.
Unfortunately I can't find any documentation on how to do this. In Objective-C it would be trivial:
#property (strong, nonatomic) UIViewController<DetailViewController>;
It appears that there isn't any syntax available in Swift to do this. The closest I've come is to declare a generic in my class definition:
class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
var detailViewController: T?
// ...
}
But then I get an error saying that "Class 'MasterViewController' does not implement its superclass's required members"
This seems like it should be as easy to do in Swift as it is in Objective-C, but I can't find anything anywhere that suggests how I might go about it.
I think you can get there by adding an (empty) extension to UIViewController and then specifying your detailViewController attribute using a composed protocol of the empty extension and your DetailViewController. Like this:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
Now all subclasses of UIViewController satisfy protocol UIViewControllerInject. Then with that, simply:
typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>
class MasterViewController : UITableViewController {
var detailViewController : DetailViewControllerComposed?
// ...
}
But, this is not particularly 'natural'.
=== Edit, Addition ===
Actually, you could make it a bit better if you define your DetailViewController using my suggested UIViewControllerInject. Like such:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
protocol DetailViewController : UIViewControllerInject { /* ... */ }
and now you don't need to explicitly compose something (my DetailViewControllerComposed) and can use DetailViewController? as the type for detailViewController.
As of Swift 4, you can now do this.
Swift 4 implemented SE-0156 (Class and Subtype existentials).
The equivalent of this Objective-C syntax:
#property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Now looks like this in Swift 4:
var detailViewController: UIViewController & DetailViewController
Essentially you get to define one class that the variable conforms to, and N number of protocols it implements. See the linked document for more detailed information.
Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
Then you inherit your view controllers from these view controllers, not the UIKit ones.
This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.

Using delegate's methods when delegate is a UIViewController in Swift

I'm not sure if this is an Xcode 6 Swift-specific problem, but here it goes.
I have two classes, MyViewController and UtilViewController. UtilViewController has a delegate property of type UIViewController, because UtilViewController is designed to be used by all of my app's viewcontrollers. It also has a function createOrder() that will only ever be called by MyViewController. Because this function will only ever be called by MyViewController, inside of createOrder() there is a line that calls a function declared by MyViewController, like this
self.delegate!.methodInMyViewController()
However this throws an error in UtilViewController
'UIViewController' does not have a member named 'methodInMyViewController'
How can I preserve the modularity of having a UIViewController delegate, but also be able to call methods from my own viewcontrollers, which are a subclass of UIViewController?
You can cast your delegate as a MyViewController to tell the compiler that it is actually a MyViewController and can call that method.
(self.delegate! as MyViewController).methodInMyViewController()
Since delegate may not always be a MyViewController, you may want to check if it is before casting:
if self.delegate! is MyViewController{
(self.delegate! as MyViewController).methodInMyViewController()
}
Instead of (ab)using the generic delegate of UtilViewController, the createOrder()
method could take a closure (callback) parameter. For example:
func createOrder(callWhenDone:()->()) {
// do stuff ...
callWhenDone()
}
From within MyViewController, you would call the method as
utilVC.createOrder {
// called from createOrder()
self.methodInMyViewController()
}