I'm new to swift/swiftui programming.
I have two environment variables that user puts in through TextFields. Based on these two text fields, I have to initialise my client. I used UserDefaults instead of the EnvironmentObject because these two fields can be considered user settings.
Here is the UserPreferences Class
class UserPreferences: ObservableObject {
@Published var accessKey: String {
didSet {
UserDefaults.standard.set(accessKey, forKey: "accessKey")
}
}
@Published var secretKey: String {
didSet {
UserDefaults.standard.set(secretKey, forKey: "secretKey")
}
}
@Published var region: String {
didSet {
UserDefaults.standard.set(region, forKey: "region")
}
}
var regions = ["us-east-1", "us-east-2"]
init() {
self.accessKey = UserDefaults.standard.object(forKey: "accessKey") as? String ?? ""
self.secretKey = UserDefaults.standard.object(forKey: "secretKey") as? String ?? ""
self.region = UserDefaults.standard.object(forKey: "region") as? String ?? "us-east-1"
}
}
Based on the accessKey and secretKey of the user, I need to create a client. I tried having this client as additional var inside the user preferences class.
var client: AWSClient {
return AWSClient(
credentialProvider: .static(accessKeyId: accessKey, secretAccessKey: secretKey),
httpClientProvider: .createNew)
}
But this isn't really a user setting. On top of that, I'm also getting the error that I need to shutdown the AWSClient before the deinit. I was able to make it work with hardcoded accessKey
and secretKey
and shutdown the client in the deinit of the class like below.
deinit {
do {
try client.syncShutdown()
} catch {
print("client shutdown error deinit")
}
}
Another way I tried is not having the client in the UserPreferences Object and instead create a new client variable in my view itself. But in a view, I have a helper function and I'm not able to do a graceful shutdown of the client as functions and structs dont have deinit in them.
But I feel like there must be a better way of initialising this client and use it in any of my views.
Thank you for your help.
Edit:
This is my preferences View.
struct PreferencesView: View {
@ObservedObject var userPreferences = UserPreferences()
var body: some View{
VStack{
Text("Preferences")
.font(.title)
HStack{
Text("Access Key:")
SecureField("Access Key", text: $userPreferences.accessKey)
}
HStack{
Text("Access Secret:")
SecureField("Access Secret", text: $userPreferences.secretKey)
}
HStack {
Picker(selection: $userPreferences.region, label: Text("Region:")) {
ForEach(userPreferences.regions, id: \.self) { region in Text(region)
}
}
Spacer()
Button{checkAWSClient(accessKey: userPreferences.accessKey, secretKey: userPreferences.secretKey)} label: {
Text("Check AWS Credentials")
}
Button{print("done button clicked")} label:{
Text("Done")
}
}
Spacer()
}.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding()
}
}
It has two text fields for the two user preference strings, that I'm storing as user defaults. And there is a button when clicked will check the connection to some external services using the user preferences.
And the function CheckAWSClient
is as follows
func checkAWSClient(accessKey: String, secretKey: String){
print("Checking aws client")
let client = AWSClient(credentialProvider: .static(accessKeyId: accessKey, secretAccessKey: secretKey), httpClientProvider: .createNew)
print(client)
let s3 = S3(client: client, region: .useast1)
s3.listBuckets()
.whenComplete {response in
switch response {
case .failure(let error):
print(error)
print("Failure s3")
case .success(let output):
print(output)
print("Success s3")
}
}
let ec2 = EC2(client: client, region: .useast1)
let describeInstancesRequest = EC2.DescribeInstancesRequest(dryRun: false)
ec2.describeInstances(describeInstancesRequest)
.whenComplete {response in
switch response {
case .failure(let error):
print(error)
print("Failure EC2")
case .success(let output):
print(output)
print("Success EC2")
}
}
}
But I'm getting an error saying I need to do client.shutdown()
in deinit. But what does it mean. I'm initialising the client in a helper function in some view.
Here is the error
Assertion failed: AWSClient not shut down before the deinit. Please call client.syncShutdown() when no longer needed.: file SotoCore/AWSClient.swift, line 95
2021-02-23 03:41:20.839170+0530 EC2 Menu Bar[3047:23906299] Assertion failed: AWSClient not shut down before the deinit. Please call client.syncShutdown() when no longer needed.: file SotoCore/AWSClient.swift, line 95
tl;dr I need to make use of user default settings that he sets and make a db connection sort of thing. So that I can do various rest queries from different views. What is the best of doing that?