I am making a chat app following a tutorial and everything was looking good except for these two errors in the same line. It might have something to do with other ViewControllers or files so just let me know.
Here is the code.
import UIKit
class SocketIOManager: NSObject {
static let sharedInstance = SocketIOManager()
var socket: SocketIOClient = SocketIOClient(socketURL: NSURL(string: "http://192.168.1.197")!)
override init() {
super.init()
}
func establishConnection() {
socket.connect()
}
func closeConnection() {
socket.disconnect()
}
func connectToServerWithNickname(nickname: String, completionHandler: (userList: [[String: AnyObject]]!) -> Void) {
socket.emit("connectUser", nickname)
socket.on("userList") { ( dataArray, ack) -> Void in
completionHandler(userList: dataArray[0] as! [[String: AnyObject]])
}
listenForOtherMessages()
}
func exitChatWithNickname(nickname: String, completionHandler: () -> Void) {
socket.emit("exitUser", nickname)
completionHandler()
}
func sendMessage(message: String, withNickname nickname: String) {
socket.emit("chatMessage", nickname, message)
}
func getChatMessage(completionHandler: (messageInfo: [String: AnyObject]) -> Void) {
socket.on("newChatMessage") { (dataArray, socketAck) -> Void in
var messageDictionary = [String: AnyObject]()
messageDictionary["nickname"] = dataArray[0] as! String
messageDictionary["message"] = dataArray[1] as! String
messageDictionary["date"] = dataArray[2] as! String
completionHandler(messageInfo: messageDictionary)
}
}
private func listenForOtherMessages() {
socket.on("userConnectUpdate") { (dataArray, socketAck) -> Void in
NSNotificationCenter.defaultCenter().postNotificationName("userWasConnectedNotification", object: dataArray[0] as! [String: AnyObject])
}
socket.on("userExitUpdate") { (dataArray, socketAck) -> Void in
NSNotificationCenter.defaultCenter().postNotificationName("userWasDisconnectedNotification", object: dataArray[0] as! String)
}
socket.on("userTypingUpdate") { (dataArray, socketAck) -> Void in
NSNotificationCenter.defaultCenter().postNotificationName("userTypingNotification", object: dataArray[0] as? [String: AnyObject])
}
}
func sendStartTypingMessage(nickname: String) {
socket.emit("startType", nickname)
}
func sendStopTypingMessage(nickname: String) {
socket.emit("stopType", nickname)
}
}
The line with the errors is,
var socket: SocketIOClient = SocketIOClient(socketURL: NSURL(string: "http://192.168.1.197")!)
Thanks.
Check if Source folder of socket.io-client swift master contains all files or not, if not you can again download that from https://github.com/socketio/socket.io-client-swift and copy source folder in your app
Go to the SocketIOClient file, open the File inspector on the right part of Xcode and see if SocketIOClient is part of your app target. The error might be caused by that.
Add import SocketIO to fix "Use of Undeclared Type SocketIOClient" error
Related
I wanna implement the function that drag a tableview cell on a "Delete Icon" to delete it.
Now my question is how can I cast my Type to NSItemProviderWriting/NSItemProviderReading to use drag and drop.
I'm following this tutorial: https://exploringswift.com/blog/creating-a-nsitemprovider-for-custom-model-class-drag-drop-api. While I failed and I still could not understand how it works.
It says that Type 'Task' does not conform to protocol 'Decodable'.('Task' is my custom model) and I also don't know what 'kUTTypeData' is in this tutorial...
Can anyone help to how to implement these protocol?
import Foundation
import CoreData
#objc(Task)
public class Task: NSManagedObject, NSItemProviderWriting, NSItemProviderReading, Codable {
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
<#code#>
}
required public init(from decoder:Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
}
public static var writableTypeIdentifiersForItemProvider: [String] {
return []
}
public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: #escaping (Data?, Error?) -> Void) -> Progress? {
let progress = Progress(totalUnitCount: 100)
do {
let encoder = JSONEncoder()
let data = try encoder.encode(self)
progress.completedUnitCount = 100
completionHandler(data, nil)
} catch {
completionHandler(nil, error)
}
return progress
}
public static var readableTypeIdentifiersForItemProvider: [String] {
return []
}
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
let decoder = JSONDecoder()
do {
let myJSON = try decoder.decode(Task.self, from: data)
return myJSON as! Self
} catch {
fatalError("Err")
}
}
}
Instead of making the NSManagedObject conform to the protocols, have you considered using .objectID.uriRepresentation() in the drag/drop handlers?
Here you can find an explanation for implementing Codable with Core Data entities:
https://stackoverflow.com/a/46917019
I'am learning swift and I see an example here https://matteomanferdini.com/network-requests-rest-apis-ios-swift/ and Im trying to change the code for something that work for me.
this is how the original code looks
struct Wrapper<T: Decodable>: Decodable {
let items: [T]?
}
protocol NetworkRequest: AnyObject {
associatedtype ModelType
func decode(_ data: Data) -> ModelType?
func load(withCompletion completion: #escaping (ModelType?) -> Void)
}
extension NetworkRequest {
fileprivate func load(_ url: URLRequest, withCompletion completion: #escaping (ModelType?) -> Void) {
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
let task = session.dataTask(with: url, completionHandler: { [weak self] (data: Data?, response: URLResponse?, error: Error?) -> Void in
if let error = error {
print("Error: \(error)")
}
guard let data = data else {
completion(nil)
return
}
completion(self?.decode(data))
})
task.resume()
}
}
class APIRequest<Resource: APIResource> {
let resource: Resource
init(resource: Resource) {
self.resource = resource
}
}
extension APIRequest: NetworkRequest {
func decode(_ data: Data) -> [Resource.ModelType]? {
let wrapper = try? JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data)
return wrapper?.items
}
func load(withCompletion completion: #escaping ([Resource.ModelType]?) -> Void) {
load(resource.request, withCompletion: completion)
}
}
but what I need to change the structure Wrapper to
struct Wrapper<T: Decodable>: Decodable {
let items: [T]?
let response: Bool?
let message: String?
}
and return items, response and message not only items
In this case you don't need the protocol at all because you want to get the root object.
This is sufficient
struct Wrapper<T: Decodable>: Decodable {
let items: [T]
let response: Bool
let message: String
}
class NetworkRequest {
func load<T : Decodable>(_ request: URLRequest, withCompletion completion: #escaping (Result<Wrapper<T>,Error>) -> Void) {
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
let task = session.dataTask(with: request) { data, _, error in
if let error = error {
completion(.failure(error))
} else {
completion( Result {try JSONDecoder().decode(Wrapper<T>.self, from: data!)})
}
}
task.resume()
}
}
The completion handler returns a Result object, on success the wrapper object and on failure all errors.
In the wrapper struct declare all properties non-optional to get error messages and change only those to optional which really can be nil.
I change the code like this
class NetworkRequest<Resource: APIResource> {
let resource: Resource
init(resource: Resource) {
self.resource = resource
}
func load(withCompletion completion: #escaping (Result<Wrapper<Resource.ModelType>,Error>) -> Void) {
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
let task = session.dataTask(with: self.resource.request) { data, _, error in
if let error = error {
completion(.failure(error))
} else {
completion( Result {try JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data!)})
}
}
task.resume()
}
}
struct LoginResource: APIResource {
typealias ModelType = Token
let methodPath = "/users/login/"
let method = "post"
var params: [String: Any]?
init(username: String, password: String) {
self.params = ["username":username, "password": password]
}
}
In my view:
func login() {
if user == "" || password == "" {
self.title_alert = "Info"
message_alert = "Test Alert"
show_alert = true
return
}
let loginRequest = NetworkRequest(resource: LoginResource(username:user,password:password))
loginRequest.load { result in
switch result {
case .failure(let error):
print(error)
case .success(let data):
print(data)
}
}
}
I don't know if this is the best way but works Thank you #vadian
I am having trouble to use the result of a completion handler.
I am getting this error "Cannot convert value of type '()' to expected argument type"
struct SearchCollectionViewModel {
let name: String
let previewURL: String?
var image:UIImage?
let dataController = DataController()
}
extension SearchCollectionViewModel {
init(with result: Result) {
self.name = result.trackName
self.previewURL = result.previewURL
if let url = result.previewURL {
let imgData = preview(with: url, completion: { data -> Data? in
guard let data = data as? Data else { return nil }
return data
})
self.image = UIImage(data: imgData)
}
}
private func preview(with url: String, completion: #escaping (Data) -> Data?) {
dataController.download(with: url) { data, error in
if error == nil {
guard let imageData = data else { return }
DispatchQueue.main.async {
_ = completion(imageData)
}
}
}
}
}
A couple of observations:
You cannot “return” a value that is retrieved asynchronously via escaping closure.
The closure definition (Data) -> Data? says that the closure not only will be passed the Data retrieved for the image, but that the closure will, itself, return something back to preview. But it’s obviously not doing that (hence the need for _, as in _ = completion(...)). I’d suggest you change that to (Data?) -> Void (or use the Result<T, U> pattern).
I’d suggest renaming your Result type as there’s a well-known generic called Result<Success, Failure> for returning .success(Success) or .failure(Failure). This is a pattern that we’ve used for a while, but is formally introduced in Swift 5, too. See SE-0235.
Your codebase can have its own Result type, but it’s an invitation for confusion later down the road if and when you start adopting this Result<T, U> convention.
You really shouldn’t be initiating asynchronous process from init, but instead invoke a method to do that.
Personally, I’d move the conversion to UIImage into the DataController, e.g.
extension DataController {
func downloadImage(with url: URL, completion: #escaping (UIImage?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, _, error in
let image = data.flatMap { UIImage(data: $0) }
completion(image, error)
}
task.resume()
}
}
So, I might suggest you end up with something like:
class SearchCollectionViewModel {
let name: String
let previewURL: String?
let dataController = DataController()
var image: UIImage?
init(with result: Result) {
self.name = result.trackName
self.previewURL = result.previewURL
}
}
extension SearchCollectionViewModel {
func preview(with url: String, completion: #escaping (UIImage?) -> Void) {
guard let urlString = previewURL, let url = URL(string: urlString) else {
completion(nil)
return
}
dataController.downloadImage(with: url) { [weak self] image, error in
DispatchQueue.main.async {
self?.image = image
completion(image)
}
}
}
}
I am about to use AlamofireObjectMapper extension to map JSON response from a server and create a func to return the object
I have wrote these code of func
func downloadPokemonDetails1(completed: DownloadComplete)-> (Pokemon?) {
let url = NSURL(string: _pokemonUrl)!
Alamofire.request(.GET, url).responseObject { (response: Response<Pokemon, NSError>) in
guard response.result.isSuccess else {
print(response.result.error.debugDescription)
return
}
let pokemon1 = response.result.value
return pokemon1
}
}
Herer is my Constanst.swift (contain DownloadComplete closure)
import Foundation
let URL_BASE = "http://pokeapi.co"
let URL_POKEMON = "/api/v1/pokemon/"
typealias DownloadComplete = () -> ()
I don't know why the func downloadPokemonDetails1 giving the error un-expected Non-void return value in void function
My Pokemon Class
lass Pokemon: Mappable {
var id: String?
var name: String?
required init?(_ map: Map){
}
func mapping(map: Map) {
name <- map["name"]
id <- map["id"]
}
}
Your code should go like this :
func downloadPokemonDetails1(completed: (Pokemon?) -> ()) {
let url = NSURL(string: _pokemonUrl)!
Alamofire.request(.GET, url).responseObject { (response: Response<Pokemon, NSError>) in
guard response.result.isSuccess else {
print(response.result.error.debugDescription)
return
}
let pokemon1 = response.result.value
completed(pokemon1)
}
}
self.downloadPokemonDetails1({
[weak weakSelf = self]
pokemon in
if let unwrappedPokemon = pokemon {
weakSelf.label.text = unwrappedPokemon.name
} else {
//show some error
}
})
In your code, you try to return value from block, not from your function. I think the better way is to return pokemon object using block.
Hope it help you
I have NSNotifications using Kugel that are working great on the watch simulator and both the iPhone and iPhone simulator to deliver messages to update the UI/state but these are failing to deliver on the watch side when testing on the devices.
The issue I believe is that the NSNotifications are triggered based on a WCSession message from the iPhone. Everything works fine on the simulator and iPhone side possibly because the connection and notifications are always delivered since the sim keep the watch app active all the time and the iPhone has full session support. On the watch there is the potential for failure of both the session and possibly the notification based on the state of the watch.
Debugging on the watch is painfully slow. It's taking 5-10 minutes just to start the debug process!
Can someone point me to some reading on how best to ensure a phone message is received on the watch and the watch app informed of the need to update based on a message? Or maybe some good debugging code that can log WCSession and NSNotification information that I can review later?
My code is fairly straightforward but still a work in progress ....
On both sides I create a singleton to manage the session, here is the phone side code:
import WatchConnectivity
import UIKit
// This class manages messaging between the Watch and iPhone
class PhoneSession: NSObject, WCSessionDelegate
{
static let manager = PhoneSession()
private var appDelegate: AppDelegate!
private let session: WCSession? = WCSession.isSupported() ? WCSession.defaultSession() : nil
private var validSession: WCSession?
{
if let session = session where session.reachable
{
return session
}
return nil
}
func startSession()
{
session?.delegate = self
session?.activateSession()
appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
}
func isEditing() -> Bool
{
if (UIApplication.sharedApplication().applicationState == .Active)
{
if (appDelegate.mainView.visible && appDelegate.mainView.currentDay.isToday())
{
return false
}
return true
}
return false
}
}
extension PhoneSession
{
func sendEditing()
{
if session!.reachable
{
sendMessage([Keys.UpdateType : PhoneUpdateType.Editing.rawValue])
}
}
func sendDoneEditing()
{
if session!.reachable
{
sendMessage([Keys.UpdateType : PhoneUpdateType.DoneEdit.rawValue])
}
}
func sendTable()
{
let tableInfo: WatchWorkout = PhoneData().buildWatchTableData()
let archivedTable: NSData = NSKeyedArchiver.archivedDataWithRootObject(tableInfo)
if session!.reachable
{
sendMessage([Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue, Keys.Workout: archivedTable])
}
else
{
do
{
try updateApplicationContext([Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue, Keys.Workout: archivedTable])
}
catch
{
print("error sending info: \(error)")
}
}
}
func sendRowDone(row: Int, done: Bool)
{
if session!.reachable
{
sendMessage([Keys.UpdateType : PhoneUpdateType.RowDone.rawValue,
Keys.RowIndex: row, Keys.Done: done])
}
else
{
let tableInfo: WatchWorkout = PhoneData().buildWatchTableData()
let archivedTable: NSData = NSKeyedArchiver.archivedDataWithRootObject(tableInfo)
do
{
try updateApplicationContext( [Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue,
Keys.Workout: archivedTable])
}
catch
{
print("error sending info: \(error)")
}
}
}
func receivedRowDone(info: [String : AnyObject])
{
let row: Int = info[Keys.Row] as! Int
let done: Bool = info[Keys.Done] as! Bool
PhoneData.manager.updateInfoFromWatch(row, done: done)
}
func receivedRowInfo(info: [String : AnyObject])
{
let row: Int = info[Keys.Row] as! Int
let rest: Int = info[Keys.Rest] as! Int
let reps: Int = info[Keys.Reps] as! Int
let force: Double = info[Keys.Force] as! Double
PhoneData.manager.updateSetInfoFromWatch(row, rest: rest, reps: reps, force: force)
}
func receivedTableDone(info: [String : AnyObject])
{
let date: Int = info[Keys.Date] as! Int
let dones: [Bool] = info[Keys.TableDones] as! [Bool]
PhoneData.manager.updateDones(dones, forDate: date)
Kugel.publish(PhoneNotificationKeys.ReloadTable)
}
func receivedTableComplete()
{
Kugel.publish(PhoneNotificationKeys.ReloadTable)
}
func receivedStartRest()
{
Kugel.publish(PhoneNotificationKeys.StartRest)
}
func receivedInfo(info: [String : AnyObject]) -> NSData?
{
let messageString: String = info[Keys.UpdateType] as! String
let updateType: WatchUpdateType = WatchUpdateType.getType(messageString)
switch (updateType)
{
case .RowInfo:
receivedRowInfo(info)
case .TableDone:
receivedTableDone(info)
case .RowDone:
receivedRowDone(info)
case .TableComplete:
receivedTableComplete()
case .StartRest:
receivedStartRest()
case .RequestUpdate:
let tableInfo: WatchWorkout = PhoneData().buildWatchTableData()
let archivedTable: NSData = NSKeyedArchiver.archivedDataWithRootObject(tableInfo)
return archivedTable
case .Ignore:
print("Opps")
}
return nil
}
}
// MARK: Interactive Messaging
extension PhoneSession
{
// Sender
func sendMessage(message: [String : AnyObject], replyHandler: (([String : AnyObject]) -> Void)? = nil, errorHandler: ((NSError) -> Void)? = nil)
{
validSession!.sendMessage(message,
replyHandler:
{
(returnMessage: [String : AnyObject]) -> Void in
if let theMessage = returnMessage[Keys.MessageStatus]
{
print("Return Message from Watch: \(theMessage)")
}
},
errorHandler:
{
(error) -> Void in
print("Error Message during transfer to Watch: \(error)")
}
)
}
func session(session: WCSession, didReceiveMessage message: [String : AnyObject])
{
self.receivedInfo(message)
}
// Receiver
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void)
{
let returnMessage = self.receivedInfo(message)
if (returnMessage != nil)
{
if let archivedTable: NSData = returnMessage!
{
let replyValues = [Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue, Keys.Workout: archivedTable] // Data to be returned
replyHandler(replyValues)
}
}
}
}
// MARK: Application Context
// use when your app needs only the latest information, if the data was not sent, it will be replaced
extension PhoneSession
{
// Sender
func updateApplicationContext(applicationContext: [String : AnyObject]) throws
{
if ((session) != nil)
{
do
{
try session!.updateApplicationContext(applicationContext)
}
catch let error
{
throw error
}
}
}
// Receiver
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject])
{
self.receivedInfo(applicationContext)
}
}
and this is the watch side:
import WatchConnectivity
class WatchSession: NSObject, WCSessionDelegate
{
static let manager = WatchSession()
private let session: WCSession? = WCSession.isSupported() ? WCSession.defaultSession() : nil
private var validSession: WCSession?
{
if let session = session where session.reachable
{
return session
}
return nil
}
func startSession()
{
session?.delegate = self
session?.activateSession()
}
}
extension WatchSession
{
func sendRowInfo(row:Int, rest: Int, reps: Int, force: Double)
{
if session!.reachable
{
let message: [String: AnyObject] = [Keys.UpdateType : WatchUpdateType.RowInfo.rawValue,
Keys.Row : row,
Keys.Rest : rest,
Keys.Reps : reps,
Keys.Force : force]
sendMessage(message)
print("sent row done to Phone: \(message)")
}
else
{
sendTableDone()
print("failed to connect to Phone, sent table done context to Phone")
}
}
func sendRowDone(row:Int, done: Bool)
{
if session!.reachable
{
let message: [String: AnyObject] = [Keys.UpdateType : WatchUpdateType.RowDone.rawValue,
Keys.Row : row,
Keys.Done : done]
sendMessage(message)
print("sent row done to Phone: \(message)")
}
else
{
sendTableDone()
print("failed to connect to Phone, sent table done context to Phone")
}
}
func sendTableDone()
{
let tableDones: [Bool] = WatchData.manager.watchTableDone()
let date: Int = WatchData.manager.date()
do
{
try updateApplicationContext( [Keys.UpdateType : WatchUpdateType.TableDone.rawValue,
Keys.Date : date, Keys.TableDones: tableDones])
}
catch _
{
print("error trying to send TableDones")
}
}
func sendTableComplete()
{
if session!.reachable
{
sendMessage([Keys.UpdateType : WatchUpdateType.TableComplete.rawValue])
}
else
{
let date: Int = WatchData.manager.date()
do
{
try updateApplicationContext( [Keys.UpdateType : WatchUpdateType.TableComplete.rawValue,
Keys.Date : date])
}
catch _
{
print("error trying to send TableComplete")
}
}
}
func sendRest() -> Bool
{
var sent: Bool = false
if session!.reachable
{
sendMessage([Keys.UpdateType : WatchUpdateType.StartRest.rawValue])
sent = true
}
return sent
}
func requestUpdate() -> Bool
{
var sent: Bool = false
if session!.reachable
{
print("requesting update reply")
sendMessage([Keys.UpdateType : WatchUpdateType.RequestUpdate.rawValue])
sent = true
}
return sent
}
func receivedUpdateReply(info: [String : AnyObject])
{
}
func receiveRowDone(info: [String : AnyObject])
{
let row: Int = info[Keys.RowIndex] as! Int
let done: Bool = info[Keys.Done] as! Bool
WatchData.manager.updateWatchTable(row, done: done)
Kugel.publish(WatchNotificationKeys.UpdateRow)
}
func receivedTable(archivedTable: NSData)
{
let workout: WatchWorkout = NSKeyedUnarchiver.unarchiveObjectWithData(archivedTable) as! WatchWorkout
WatchData.manager.updateWatchWorkout(workout)
Kugel.publish(WatchNotificationKeys.ReloadTable)
}
func receivedStartEditStatus()
{
Kugel.publish(WatchNotificationKeys.StartEdit)
}
func receivedDoneEditStatus()
{
WatchData.manager.retrieveWorkout()
Kugel.publish(WatchNotificationKeys.DoneEdit)
}
func receivedStopRest()
{
Kugel.publish(WatchNotificationKeys.StopRest)
}
func receivedInfo(info: [String : AnyObject])
{
let messageString: String = info[Keys.UpdateType] as! String
let updateType: PhoneUpdateType = PhoneUpdateType.getType(messageString)
switch (updateType)
{
case .TableInfo:
receivedTable(info[Keys.Workout] as! NSData)
case .Editing:
receivedStartEditStatus()
case .DoneEdit:
receivedDoneEditStatus()
case .RowDone:
receiveRowDone(info)
case .StopRest:
receivedStopRest()
case .Ignore:
print("Opps")
}
}
func receivedReply(info: [String : AnyObject])
{
if let replyString: String = info[Keys.ReplyType] as? String
{
let replyType: ReplyType = ReplyType.getType(replyString)
switch (replyType)
{
case .Table:
print("received Reply Table")
receivedTable(info[Keys.Workout] as! NSData)
case .NoData:
print("Opps ... nodata in reply")
case .Ignore:
print("Opps replyType message error")
}
}
}
}
// MARK: Interactive Messaging
extension WatchSession
{
// Sender
func sendMessage(message: [String : AnyObject], replyHandler: (([String : AnyObject]) -> Void)? = nil, errorHandler: ((NSError) -> Void)? = nil)
{
validSession!.sendMessage(message,
replyHandler:
{
(replyMessage: [String : AnyObject]) -> Void in
if let typeMessage: String = replyMessage[Keys.ReplyType] as? String
{
self.receivedReply(replyMessage)
print("Return Message from Phone: \(typeMessage)")
}
},
errorHandler:
{
(error) -> Void in
print("Error Message during transfer to Phone: \(error)")
}
)
}
// Receiver
func session(session: WCSession, didReceiveMessage message: [String : AnyObject])
{
self.receivedInfo(message)
}
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void)
{
self.receivedInfo(message)
let replyValues = [Keys.MessageStatus : "Watch received message"] // Data to be returned
replyHandler(replyValues)
}
}
// MARK: Application Context
extension WatchSession
{
// Sender
func updateApplicationContext(applicationContext: [String : AnyObject]) throws
{
if let session = validSession
{
do
{
try session.updateApplicationContext(applicationContext)
}
catch let error
{
throw error
}
}
}
// Receiver
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject])
{
// handle receiving application context
receivedInfo(applicationContext)
}
}
I create the singleton in my AppDelegate on the iPhone side and the ExtensionDelegate on the watch side, here is the phone side:
var phoneSession: PhoneSession!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
self.phoneSession = PhoneSession()
PhoneSession.manager.startSession()
The basic logic when sending a message is it looks if the other side is reachable, if it is sendMessage is used, if it is not reachable then sendApplicationContext is used.
When the message is received on the phone side there is some extra logic to see if the app is in the foreground or background, if in foreground it will push a notification onto the main thread, if in background just the info is updated. On the watch side it always pushes onto the main thread since my understanding is messages will not be received in the background.