Socket IO iOS sdk confuses xCode - swift

installed socket.io sdk using cocoapods:
pod 'Socket.IO-Client-Swift'
Once I import it
import SocketIO
I get this weird warning and whenever I run the app it crashes:
item is referred as the following:
func createChatBox(item: AnyObject) -> UIView {
message.text = (item["message"] as! String)
}
And called as the following:
createChatBox(item: messages[0] as AnyObject)
Where
var messages:[Dictionary<String, AnyObject>] = [Dictionary<String, AnyObject>]()
With declaration
messages = [["type": 1 as AnyObject, "message" : "Hello" as AnyObject]]
Everything works fine without import SocketIO, I don't really know what is the problem with SocketIO and my variables.
Also, accessing the data directly without my functions works fine, as the following:
print(messages[0]["message"] as! String)
Thanks in advance.

Related

Trying to figure out Swift Clients for Thrift

I want to utilize thrift from within my new MacOS App. The app is working fine so far as a menubar app.. it takes in a string and lets you save it to memory somewhere... if you click on the clipboard button it saves your string to clipboard.
What I do not understand is.. if I've generated some Swift Client code via the
thrift --gen swift <name_of_thrift_file.thrift>
I get two .swift files, as expected.. AND instructions from the github to rig up the Client object.. here's my Client Object so far.. but I am seeing a error already with the example code. I want to add a status button to the menubar app (anywhere) .. which calls my thrift server for a ping() and goes green once response looks good.
Targeting : Mac OS 12.x+
Thrift Version : v0.16.0
XCode Version : 13.x
happily I hand rolled the library (Thrift) into my project.. for some reason I think the package mangement didn't work.. once added it was a breeze to generate my .thrift files
thrift --gen swift <my_thrift_service>.thrift
once I buttoned all that together in XCode.. the last part was getting a client that worked.. the example in git was showing an error but I got past it with this
AWSBotor3ThriftClient.swift
import Foundation
class AWSBoto3ThriftClient {
var boto3_thrift_client :aws_boto3_accessorClient?
var server_status :Int32
init() {
do {
let transport = try TSocketTransport(hostname: "localhost", port: 9090)
let proto = TBinaryProtocol(on: transport)
let client = aws_boto3_accessorClient(inoutProtocol: proto)
self.boto3_thrift_client = client
self.server_status = try self.boto3_thrift_client!.ping()
} catch {
print("init had a boo boo :(")
self.server_status = 333
self.boto3_thrift_client = nil
}
print(self.server_status)
}
}
S3SyncAppApp.swift
import SwiftUI
#main
struct S3SyncAppApp: App {
#NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#State var currentNumber: String = "1"
var my_little_client: AWSBoto3ThriftClient = AWSBoto3ThriftClient()
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

Spawning a process in an app built with UIKit for macOS (Catalyst)

I'm building an application that shares most of the code between macOS and iOS versions (targeting macOS 11 and iOS 14). UIKit for Mac seems like a natural choice to help with this. Unfortunately, one of the libraries uses the Process type under the hood. Building it produces "Cannot find type Process in scope" error when a dependency on it is added and when targeting macOS. I'm fine with excluding this library for iOS, but I still need to link with it on macOS while keeping the ability to use UIKit on all platforms.
I've selected this library to be linked only for macOS in Xcode, but this has no effect and the same build error persists. Also, I'm getting this error without adding a single import SwiftLSPClient statement in the app, so I don't think conditional imports would help in this case.
What would be the best way to resolve this issue within the constraints listed above?
I created a LSPCatalyst class in my Mac Catalyst app to replace the MacOS LanguageServerProcessHost. To make that work, I replaced the process property with a processProxy that accesses the process instance in a MacOS bundle using the FoundationApp protocol as explained below.
Following #Adam's suggestion, I created a MacOS bundle to proxy for the process instance. You follow the same idea as he pointed to for AppKit access from Catalyst apps, but you just need Foundation to get access to Process. I called the bundle FoundationGlue and put everything in a FoundationGlue folder in my Xcode project. The bundle needs an Info.plist that identifies the principal class as "FoundationGlue.MacApp", and the MacApp.swift looks like:
import Foundation
class MacApp: NSObject, FoundationApp {
var process: Process!
var terminationObserver: NSObjectProtocol!
func initProcess(_ launchPath: String!, _ arguments: [String]?, _ environment: [String : String]?) {
process = Process()
process.launchPath = launchPath
process.arguments = arguments
process.environment = environment
}
func setTerminationCompletion(_ completion: (()->Void)!) {
let terminationCompletion = {
NotificationCenter.default.removeObserver(self.terminationObserver!)
completion?()
}
terminationObserver =
NotificationCenter.default.addObserver(
forName: Process.didTerminateNotification,
object: process,
queue: nil) { notification -> Void in
terminationCompletion()
}
}
func setupProcessPipes(_ stdin: Pipe!, _ stdout: Pipe!, _ stderr: Pipe!) {
process.standardInput = stdin
process.standardOutput = stdout
process.standardError = stderr
}
func launchProcess() {
process.launch()
print("Launched process \(process.processIdentifier)")
}
func terminateProcess() {
process.terminate()
}
func isRunningProcess() -> Bool {
return process.isRunning
}
}
The corresponding header I called FoundationApp.h looks like:
#import <Foundation/Foundation.h>
#protocol FoundationApp <NSObject>
typedef void (^terminationCompletion) ();
- (void)initProcess: (NSString *) launchPath :(NSArray<NSString *> *) arguments :(NSDictionary<NSString *, NSString *> *) environment;
- (void)setTerminationCompletion: (terminationCompletion) completion;
- (void)setupProcessPipes: (NSPipe *) stdin :(NSPipe *) stdout :(NSPipe *) stderr;
- (void)launchProcess;
- (void)terminateProcess;
- (bool)isRunningProcess;
#end
And the FoundationAppGlue-Bridging-Header.h just contains:
#import "FoundationApp.h"
Once you have the bundle built for MacOS, add it as a framework to your Mac Catalyst project. I created a Catalyst.swift in that project for access to the FoundationGlue bundle functionality::
import Foundation
#available(macCatalyst 13, *)
struct Catalyst {
/// Catalyst.foundation gives access to the Foundation functionality identified in FoundationApp.h and implemented in FoundationGlue/MacApp.swift
static var foundation: FoundationApp! {
let url = Bundle.main.builtInPlugInsURL?.appendingPathComponent("FoundationGlue.bundle")
let bundle = Bundle(path: url!.path)!
bundle.load()
let cls = bundle.principalClass as! NSObject.Type
return cls.init() as? FoundationApp
}
}
Then, you use it from your app like:
let foundationApp = Catalyst.foundation!
foundationApp.initProcess("/bin/sh", ["-c", "echo 1\nsleep 1\necho 2\nsleep 1\necho 3\nsleep 1\necho 4\nsleep 1\nexit\n"], nil)
foundationApp.setTerminationCompletion({print("terminated")})
foundationApp.launchProcess()
This is a messy solution but I know it works: Add a “Mac bundle” to your Catalyst app and import the MacOS-only framework with that.
Here’s a guide to creating and loading a Mac bundle: https://medium.com/better-programming/how-to-access-the-appkit-api-from-mac-catalyst-apps-2184527020b5
Once you have the bundle, you can add Mac-only libraries and frameworks to it. You’ll have to bridge data and method calls between the bundle and your iOS app, but it’s manageable.

Why can't my app find Firebase Functions?

I can't figure out why I keep getting the Swift warning: Use of unresolved identifier 'Functions on this line of my code: let functions = Functions.functions()
My imports for the viewController includes import Firebase and it works fine when I declare let db = Firestore.firestore() right above the line let functions = Functions.functions()
My podfile includes pod 'Firebase/Functions' and I've installed the pod.
I'm calling functions later using the following code and when I type "functions" it recommends adding .httpsCallable which leads me to believe that it actually does recognize the object "functions":
func getData(){
functions.httpsCallable("helloWorld").call(userData) { (result, error) in
if let error = error {
print(error)
}
if let data = result?.data {
print(data)
}
}
}
Figured it out. Importing Firebase is not enough, one must also import FirebaseFunctions (despite what Swift thinks, see screenshot below).

Swift Privileged Helper (XPC Listener) Crashing with Illegal Instruction Error

I’ve created a Swift macOS app which uses SMJobBless to create a helper with escalated privileges. This works fine—the helper gets installed to /Library/Privileged Helper Tools and an accompanying LaunchDaemon gets created in /Library/LaunchDaemons. However, the helper is unable to start successfully. Instead, it crashes with an “Illegal instruction: 4” message.
I’ve prepared the helper to respond to XML connections by implementing the NSXPCListenerDelegate protocol. Here‘s my Helper main.swift code:
import Foundation
class HelperDelegate: NSObject, NSXPCListenerDelegate {
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
newConnection.exportedInterface = NSXPCInterface(with: HelperToolProtocol.self)
newConnection.exportedObject = HelperTool()
newConnection.resume()
return true
}
}
let delegate = HelperDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
The crash occurs on the last line, listener.resume().
I tried to launch the helper app manually from the command line (which is identical to what the LaunchDaemon does) and, again, it crashes with the above error message printed to stdout. I don’t have any more ideas on how to test this for the root cause. My implementation is more than rudimentary, following Apple’s guidlines for implementing XM services. Also, the various posts on SO regarding XML services haven’t helped me in resolving this issue. Has anyone of you tried to create a privileged helper in Swift successfully? BTW, the app is not sandboxed.
For the sake of completeness, here’s the code for the HelperTool class referenced in my HelperDelegate class above:
import Foundation
class HelperTool: NSObject, HelperToolProtocol {
func getVersion(withReply reply: (NSData?) -> ()) {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString" as String) as? String ?? "<unknown version>"
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "<unknown build>"
if let d = "v\(version) (\(build))".data(using: .utf8, allowLossyConversion: false) {
reply(d as NSData)
}
}
}
And finally the HelperToolProtocol:
import Foundation
#objc(HelperToolProtocol) protocol HelperToolProtocol {
func getVersion(withReply: (NSData?) -> ())
}
Thanks for any help!
After days of testing I finally found a solution which makes my XPC helper launch correctly and respond to any messages. The problem lies in the last three lines of the main.swift module which currently read
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
which, as put in the question, make the helper crash immediately upon the very last line.
I took these lines directly from Apple’s Creating XPC Services documentation. Here’s the documentation for the NSXPCListener resume() function:
If called on the service() object, this method never returns. Therefore, you should call it as the last step inside the XPC service's main function after setting up any desired initial state and configuring the listener itself.
The solution is to not call the NSXPCListener.service() singleton object but rather instantiate a new NSXPCListener object using the init(machServiceName:)initializer passing the same Mach service name that is being used on the main app’s XPC connection. As resume() in this case would resume immediately—thus terminating the helper—you have to put it on the current run loop to have it run indeterminately. Here’s the new, working code:
let listener = NSXPCListener(machServiceName: "Privilege-Escalation-Sample.Helper")
listener.delegate = delegate
listener.resume()
RunLoop.current.run()

Why can't I remove the NSUserDefaults key in swift?

When I run the following test case, the testRemovePref method fails as it doesn't actually remove the value. I'm using Xcode 7.2. Why is this happening?
EDIT: This is only occurring when the tests belong to a Framework Library. The tests below seem to work fine when run in an Application. Odd.
import XCTest
class NSUserDefaultsTests: XCTestCase {
func testSetPref() {
let prefs = NSUserDefaults.standardUserDefaults()
prefs.setValue("value1", forKeyPath: "testKey")
let val : String? = prefs.stringForKey("testKey")
print("value=\(val)") // prints "value1"
XCTAssertEqual("value1", val)
}
func testRemovePref() {
let prefs = NSUserDefaults.standardUserDefaults()
prefs.removeObjectForKey("testKey")
let val : String? = prefs.stringForKey("testKey")
print("value=\(val)") // prints "value1"
XCTAssertNil(val)
}
}
This is only occurring when the tests belong to a Framework Library.
The tests below seem to work fine when run in an Application.
An application automatically synchronizes defaults when you send it to the background. This doesn't happen with tests. Try adding:
prefs.synchronize()