0

I made a watchOS connectivity application and it works. Now I'm trying to make a dedicated classes for Connection at iPhone and Watch. For the iPhone connectivity class I have this (I also have other methods for transferring data but the problem is here):

import UIKit
import WatchConnectivity

class iPhoneConnectivity: UIViewController, WCSessionDelegate {

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

    }

    func sessionDidBecomeInactive(_ session: WCSession) {

    }

    func sessionDidDeactivate(_ session: WCSession) {

    }

    var session : WCSession!;

    func getPrepared() {
        if (WCSession.isSupported()) { 
            // check if the watch connectivity is suported on device
            self.session = WCSession.default;
            self.session.delegate = self;
            self.session.activate();
        } else {
            print("Session is not supported")
        }
    }
}

The problem is that when I try to call this method in ViewController

connect.getPrepared();

The application quits unexpectedly.

I have a global variable

var connect: iPhoneConnectivity!;

Is that because I didn't initialize the connect variable? If that's the problem, how should I initialized it?

In original application, which works, I have this code of getPrepared() method in ViewController's method didLoad()

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • 1
    Can you edit your question to show how/where you do initialize `iPhoneConnectivity` from the calling view controller? I assume that has to happen before you call `connect.getPrepared()`. Also, in Swift, you do not need to put semicolons ("`;`") after each line of code (semicolons are an Objective-C must). – Michael Dautermann Aug 02 '17 at 08:23
  • 1
    Adding to what @MichaelDautermann has already said, I don't think your class should inherit from `UIViewController`. Following the `MVC` design pattern this class should be a Model class and hence be completely independent of any UI related tasks. I also don't see any UI related code in your class, so inheriting from `UIViewController` doesn't make any sense and is not needed. Moreover, for such a class I think creating `iPhoneConnectivity` as a singleton is a better approach. – Dávid Pásztor Aug 02 '17 at 09:28
  • I Dont initialise the variable 'connect'. I use it just for calling the function getPrepared() because I can't do that in a static way. I know that iPhoneConnectivity should be a model class but I get some errors when I stop inherit from UIViewController. I also know that the semicolons are optionals, but I like this way. But could the fact that I inherit form UIViewcontroller be the problem I have? I don't have errors, the app is compiled, but quite unexpectedly. –  Aug 02 '17 at 09:35
  • The problem is not caused by inheriting from `UIViewController`, it is caused by accessing an implicitly unwrapped optional without first giving it a non-nil value. However, making a model class inherit from `UIViewController` is really bad practice, so you should definitely not do is. What errors did you get when not doing it? About the optional usage of semicolons in Swift: it might be optional, so you can use it, but if you ever start working with Swift in a team, people will definitely don't like when you put semicolons at the end of lines unless you put several statements in the same line – Dávid Pásztor Aug 02 '17 at 10:54
  • Until you get really familiar with using optionals and especially knowing when you can unsafely unwrap them, I would not recommend using implicitly unwrapped optionals, since they can cause trouble if you don't know how to use them and it is harder to debug them than if you using normal optionals. – Dávid Pásztor Aug 02 '17 at 10:57

1 Answers1

1

The issue is that connect is an implicitly unwrapped optional and you call a function on it without actually initializing it. Implicitly unwrapped optionals are still optionals and hence if you don't give them a value, they are nil by default. Hence when you try to access them without giving them a non-nil value first, you will get a runtime exception.

Define connect as a singleton and not as a global variable.

class iPhoneConnectivity: WCSessionDelegate {

    static let sharedInstance = iPhoneConnectivity()

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}

    func sessionDidBecomeInactive(_ session: WCSession) {}

    func sessionDidDeactivate(_ session: WCSession) {}

    var session : WCSession!;

    func getPrepared() {
        if (WCSession.isSupported()) { 
            // check if the watch connectivity is suported on device
            self.session = WCSession.default;
            self.session.delegate = self;
            self.session.activate();
        } else {
            print("Session is not supported")
        }
    }
}

You can access it using iPhoneConnectivity.sharedInstance and call getPrepared() using iPhoneConnectivity.sharedInstance.getPrepared().

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116