Trying to figure out Swift Clients for Thrift - swift

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()
}
}
}

Related

SwiftUI ShareLink share custom data

I am trying to share a custom struct between two users within the App via ShareLink (UIActivityViewController) in SwiftUI. I created a custom Document Type, the Exported Type Identifier and marked the struct as Transferable.
However, while I am able to save the example to a file, I would like to send it to another user via AirDrop or similar, s.t. the App appears as an Application Activity.
import SwiftUI
import UniformTypeIdentifiers
struct SwiftUIView: View {
#State private var customStruct: CustomStruct = CustomStruct()
var body: some View {
ShareLink(item: customStruct, preview: SharePreview(customStruct.name))
}
}
struct CustomStruct: Codable {
var name: String = "Test Example"
var description: String = "Test"
}
extension CustomStruct: Transferable {
static var transferRepresentation: some TransferRepresentation {
CodableRepresentation(contentType: .customStruct)
}
}
extension UTType {
static var customStruct: UTType { UTType(exportedAs: "com.TestExample.CustomStruct") }
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
Have you tried setting the "Conforms To" value in "Exported Type Identifiers" to public.json instead of public.data? After all, your custom struct conforms to Codable and can thus be serialized into JSON. For me this did the trick and Messages started showing up in the share sheet. When running on a device, I also see AirDrop.
What I’m still struggling with is how the receiving app can actually handle the file. I added the LSSupportsOpeningDocumentsInPlace key to Info.plist and set it to YES which causes the file to open in my app by tapping, but then I’m a bit stuck. Maybe onOpenURL: and decode the JSON file that the URL points to? I found zero results on the internet for this, which is a bit surprising.

Swift debugQuickLookObject Xcode 12.4

I'm trying to test debugQuickLookObject I'm using Xcode 12.4 but the sample code given doesn't return a String in the QuickLook Debugger or the console, is debugQuickLookObject still valid?
class User {
var name = "Duane Dibbley"
var age = 28
#objc func debugQuickLookObject() -> Any? {
return "My name is \(name) and I'm \(age)."
}
}
I've tried inheriting from NSObject - no joy, I can't even confirm if the method signature is correct :-s
Code from here: https://www.hackingwithswift.com/example-code/language/how-to-create-quick-look-debug-previews-for-your-custom-types
I managed to get the code working, but only for iOS based projects, code can be found here:
https://github.com/nthState/RealityKitDebugger
I wish I knew why macOS based projects don't work as expected.

Is viewContext different between Swift and SwiftUI

EDIT: I've added a rewording of my question at the bottom.
So I have an app that I've been working on for a long time. I used it to teach myself Xcode / Swift and now that I have a Mac again, I'm trying to learn SwiftUI as well by remaking the app completely as a new project.
I have an Entity in CoreData that only ever contains 1 record, which has all of the attributes of the settings I'm tracking.
Before, I was able to make an extension to my Entity, Ent_Settings that would allow me to always get that specific record back.
class var returnSettings: Ent_Settings {
//this is inside of extension Ent_Settings
let moc = PersistenceController.shared.container.viewContext
var settings: Ent_Settings?
let fetchRequest: NSFetchRequest<Ent_Settings> = Ent_Settings.fetchRequest()
do {
let results = try moc.fetch(fetchRequest)
if results.count == 0 {
Ent_Settings.createSettingsEntity()
do {
let results = try moc.fetch(fetchRequest)
settings = results.first!
} catch {
error.tryError(tryMessage: "Failed performing a fetch to get the Settings object after it was created.", loc: "Ent_Settings Extension")
}
} else {
settings = results.first!
}
} catch {
error.tryError(tryMessage: "Fetching Settings Object", loc: "Ent_Settings Extension")
}
return settings!
}
It took me a while to figure out how to get the moc now that there is no AppDelegate, but you can see I figured out in the code and that seems to work great.
However, when I go to a View that I made in SwiftUI, I'm getting weird results.
In the Simulator, I can run my app and see the changes. Leave the view and come back and see the changes are saved. However, if I rebuild and run the app it loses all data. So it seems it's not remembering things after all. Basically, it's volatile memory instead of persistent memory. But if I put another function in the extension of Ent_Settings to update that attribute and then build and run again, it will persistently save.
I'm wondering if it has something to do with how the context is managed, perhaps it's not seeing the changes since it is a different "listener"?
Here is what I'm doing to make the changes in the View. (I tried removing the extra stuff that just made it harder to see)
import SwiftUI
struct Settings_CheckedView: View {
#Environment(\.managedObjectContext) private var viewContext
#State private var picker1 = 0
var body: some View {
Form {
Section(header: Text("..."),
footer: Text("...")) {
VStack {
HStack { ... }
Picker("", selection: $picker1) {
Text("Off").tag(0)
Text("Immediately").tag(1)
Text("Delay").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.onChange(of: picker1, perform: { value in
settings.autoDeleteSegment = Int16(value)
viewContext.trySave("Updating auto-delete segment value in Settings",
loc: "Ent_Settings Extension")
})
}
}
...
...
.onAppear(perform: {
settings = Ent_Settings.returnSettings
self.picker1 = Int(settings.autoDeleteSegment)
self.picker2 = Int(settings.deleteDelaySegment)
})
}
}
And here is the code that I'm using for the trySave() function I have on the viewContext
extension NSManagedObjectContext {
func trySave(_ tryMessage: String, loc: String) {
let context = self
if context.hasChanges {
do {
try self.save()
} catch {
print("Attempted: \(tryMessage) -in \(loc)")
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
This code doesn't seem to actually save anything to the Database.
I also tried adding this code into Settings_CheckedView to see if that would make a difference, but I got even weird results.
#FetchRequest(sortDescriptors:[])
private var settingsResult: FetchedResults<Ent_Settings>
But that returns zero results even though I know the Ent_Settings has 1 record. So that makes me wonder if I am actually creating two databases with the way I'm doing it.
I'm really new to SwiftUI and CoreData seems to be one of those things that is hard to get information about. Hoping someone can point out where I'm going wrong. I'd love to be able to make CoreData changes in both Swift and SwiftUI.
Thank you for any help you can give and let me know if you need anything else added in.
EDITED: To try to reword question
So ultimately, I'm wanting to do some stuff with CoreData inside of the extension for that entity. My database has a lot of aspects to it, but I also made an entity in there to store settings information and since that one isn't related to anything else, I figured that would be a good starting point in learning SwiftUI. I have everything working in UIKit, but I'm specifically trying to learn SwiftUI as well.
From how I understand SwiftUI, it is meant to replace the storyboard and make the lifecycle stuff much easier. So classes I have that deal with CoreData should still do that external to SwiftUI.
As you can see above in my Settings_CheckedView view above, I'm referencing that single settings record from an extension in Ent_Settings. Basically, everything inside of that extension takes care of returning that single record of Settings, checking if that record exists and creating it if it doesn't (first time running app basically)
Ideally, I'd like to keep the functionality inside the extension of Ent_Settings, but my problem is I can't get the correct instance of the moc to persistently save it.
#main
struct MyApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
MainMenuView().onAppear(perform: {
if Ent_Lists.hasAnyList(persistenceController.container.viewContext) == false {
Ent_Lists.createAnyList(persistenceController.container.viewContext)
}
if Ent_Section.hasBlankSection(persistenceController.container.viewContext) == false {
Ent_Section.createBlankSection(persistenceController.container.viewContext)
}
//self.settings = Ent_Settings.returnSettings(persistenceController.container.viewContext)
})
//ContentView()
//.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
I'm pretty certain that let persistenceController = PersistenceController.shared is initializing the persistent controller used throughout the app. Either creating it or retrieving it.
So, I tried this first inside of Ent_Settings:
let moc = PersistenceController.shared.container.viewContext
but I think that this might be creating a new PersistenceController outside the one made inside of MyApp
I also tried let moc = EZ_Lists_SwiftUI.PersistenceController.shared.container.viewContext but I'm pretty sure that also makes a new instance given I can only access the upper case PersistenceController and not the lower case one.
I also tried just passing the moc from the view like this: class func createSettingsEntity(_ moc: NSManagedObjectContext) { but I get an error about the moc being nil, so I'm guessing the moc can't be sent by reference from a Struct.
Thread 1: "+entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name 'Ent_Settings'"
And just to be clear, I'm adding this to the view: #Environment(\.managedObjectContext) private var viewContext adding this #State property to the View: #State private var settings: Ent_Settings! and setting it within .onAppear with this: self.settings = Ent_Settings.returnSettings(self.viewContext)
So what I'm really looking for is how I access the moc from within that extension of Ent_Settings. In my app that was purely UIKit and Storyboards I used this: let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext but as there is no longer an AppDelegate, I cannot use that anymore. What replaces this to get moc when you are doing SwiftUI but working outside of the Views, like in a class or something like I am? Thank you. Hopefully this extra information helps explain my issue.
If you are only using coredata to store settings, I would look into UserDefaults and if that matches your use case.
https://developer.apple.com/documentation/foundation/userdefaults
If you for some reason need to use CoreData, I would recommend enabling CloudKit, as CloudKit will allow you to actually view what data is saved via a web console.
Also, SwiftUI does not create an AppDelegate for you, you are still able to just create your own AppDelegate.swift file as you would with UIKit.
Just define the #UIApplicationDelegateAdaptor to your custom AppDelegate.swift file in your top most struct (the one with #main) before the struct declaration.
#main
struct MainAppView: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
Okay, a bit of egg on my face. I finally figured out why I was having so much trouble. When I was making my app, I commented out everything related to the apple provided ContextView and commented out too much.
//ContentView()
//.environment(\.managedObjectContext, persistenceController.container.viewContext)
I lost the part where the environment object was getting setup. After putting that back in I'm able to save to the moc now.
In my Entity class extension I'm accessing the moc this way:
let moc = MyApp.PersistenceController.shared.container.viewContext
Thank you for everyone who looked and tried to help. Turns out I was shooting myself in the foot.

Setting variables with custom class using Websockets and vapor

I am trying to setup a simple vapor web socket. My issue is that I need to maintain the web sockets that are open. In order to do that they need to be stored in a variable. Here is my current code:
import Vapor
var test = [Instance]()
final class Instance {
var socket:WebSocket
var message:String = ""
var id:String = ""
}
extension Droplet {
func setupRoutes() throws {
get("hello") { req in
var json = JSON()
try json.set("hello", "world")
return json
}
}
//Socket code goes here as well
}
I keep getting an error while trying to run my project saying, Use of unresolved identifier 'Instance', Why am I getting this error and how do I fix it? What is the best practicing while using web sockets with vapor?

Socket IO iOS sdk confuses xCode

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.