How to save custom objects to Firestore? - swift

Hello Everyone I have a quick question. I'm trying to save a custom model to Firestore like so:
import Firebase
let city = City(name: "Los Angeles",
state: "CA",
country: "USA",
isCapital: false,
population: 5000000)
do {
try db.collection("cities").document("LA").setData(from: city)
} catch let error {
print("Error writing city to Firestore: \(error)")
}
The issue is .setData(from: city) is not working? Its saying Extraneous argument label 'from:' and when I do I get an error. Did Firestore deprecate this or do I have to import something else?
Thank you

The documentation isn't exactly wrong on this, it' just incomplete in one section. Firebase added an extension to make crafting custom obects easier but didn't mention that extension in the documentation. (I assume its an extension)
The documentation on Custom Objects is an example of the code that needs the extension
Simple fix by adding this to your podfile
pod 'FirebaseFirestoreSwift'
and then do a pod update either in terminal or cocoapods.
Then in your Class just update the imports to include that
import Cocoa
import FirebaseCore
import FirebaseFirestore
import FirebaseFirestoreSwift
For reference the code in the docs was this
try db.collection("cities").document("LA").setData(from: city)
and this
let docRef = db.collection("cities").document("LA")
docRef.getDocument { (document, error) in
let result = Result {
try document.flatMap {
try $0.data(as: City.self)
}
}
and this line
.data(as: City.self)
and
.setData(from:
were the 'troublemakers' that needed the FirebaseFirestoreSwift

Related

Create a Flutter plugin in swift to export realm data

We have a native iOS app that has a Realm database. Now we have developed a new Flutter app that will substitute the native iOS app. When an user upgrade native iOS app to the new Flutter app, we want to migrate the existing Realm database content into the new Sqflite database.
We have created a Flutter plugin with swift to export Realm data to json. At the moment, we were able to add RealmSwift dependency to the plugin, but when we run the below code, it throws Cannot find 'DeviceModel' in scope.
Any idea to get all rows from DeviceModel table? To acomplish that is necesary to add some Realm schema manually?
import Flutter
import UIKit
import RealmSwift
enum PluginError: Error {
case notImplemented
}
public class SwiftRealmToJsonPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "realm_to_json", binaryMessenger: registrar.messenger())
let instance = SwiftRealmToJsonPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: #escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
case "realmInfoExist":
result(check_data())
default:
result(FlutterMethodNotImplemented)
}
}
// check if Realm exists
func check_data() -> Bool {
let realm = try! Realm()
let devices = realm.objects(DeviceModel.self)
}
}
The solution was:
Change plugin language from Swift to Objective-C and copy and paste all Realm models.
Implement in each model class a method to generate a dictionary with it data.
Export dictionary to json.
Right now we are able to export Realm info into a json format. Next step is implement the migration logic to adapt a table-less structure to sql.
Thanks to #Jay to point me out on the good direction to get a solution.

Cannot find type 'ListenerRegistration' in scope

Can't quite understand why this isn't working.
I have:
Import Firebase
...up at the top. Followed by:
class MessageViewController: MessagesViewController
{
private var messages: [Message] = []
private var messageListener: ListenerRegistration?
And it's giving me the error:
Cannot find type 'ListenerRegistration' in scope
I checked the docs and ListenerRegistration doesn't appear to be deprecated... so why is this happening?
ListenerRegistration is part of the FirebaseFirestore package. You will need to:
import FirebaseFirestore

Sharing Data with AppGroup

I want to share one variable from my UIKit File to my Widget Extension created with SwiftUI.
I followed this here. Please look at the answer from J Arango.
But i dont understand the last part there.
I have to use import MySharedObjects.
So I did this:
import MySharedObject
struct testing {
let mySharedObject = MySharedObject(name: "My Name", lastName: "My Last Name")
do {
let data = try JSONEncoder().encode(mySharedObject)
/// Make sure to use your "App Group" container suite name when saving and retrieving the object from UserDefaults
let container = UserDefaults(suiteName:"group.com.widgetTest.widgetContainer")
container?.setValue(data, forKey: "sharedObject")
/// Used to let the widget extension to reload the timeline
WidgetCenter.shared.reloadAllTimelines()
} catch {
print("Unable to encode WidgetDay: \(error.localizedDescription)")
}
}
But I get the following errors.
Extra argument at position #1, #2 in call
Missing argument for parameter from call
insert from : <#Decoder#>
expected declaration where I use the do part.
Save data to UserDefaults in your main App:
UserDefaults(suiteName: <your_app_group>)!.set("test", forKey: "test")
Read data from UserDefaults in your Widget:
let testStr = UserDefaults(suiteName: <your_app_group>)!.string(forKey: "test")
If you want to save other types see:
How can I use UserDefaults in Swift?

How to design Complications for watchOS 6 independent app?

I have an independent application on watchOS 6 and in my app I am using the Firestore REST API to show the data to the user using URLSession.
Since the Cloud Firestore REST API returns a JSON string, in order to process the data, I have created nested structs. Example: To access the 'title' in a particular response, I do something like this: response.mapValue.fields.title.stringValue.
The app works fine for now. In the long run I plan on creating the URLSessions as background tasks. Right now, I am calling URLSession every time the view is rendered by using .onAppear(functionToUseURLSession())) on my data's List view.
Now the next thing I want to implement is the complication for this particular app.
I am new to Swift and SwiftUI and am having the hardest time just getting started. All the tutorials I've been through online use WKExtensionDelegate to get the data models for the complication.
But in my case, I don't even have a data model! I just have structs calling other structs in a nested fashion in order to process the JSON response I get from the API call.
Any help allowing me to understand this is highly appreciated!
Here is some code to better understand the structure of the App:
struct Firebase: Codable {
var name: String?
var createTime, updateTime: String?
var fields: FirebaseFields
}
Now, FirebaseFields is also another struct:
struct FirebaseFields: Codable {
var emailID, lastName, firstName: String?
var goalsRoutines: GoalsRoutines
enum CodingKeys: String, CodingKey {
case emailID = "email_id"
case lastName = "last_name"
case firstName = "first_name"
}
}
Similarly, GoalsRoutines is also a struct...
As mentioned above, I have made these structs to follow the exact structure of the JSON object is get in response from Firebase API. So I access fields like: Firebase.FirebaseFields.GoalsAndRoutines.whatever.is.my.firebase.schema
My GoalsView.swift is:
var body: some View {
List{
...
...
}.onAppear{
FirebaseServices.getFirebaseData() {
(data) in self.data = data
}
}
}
And finally, in FirebaseServices.swift, func getFirebaseData is:
func getFirebaseData(completion: #escaping ([Value]) -> ()) {
guard let url = URL(string: "FIRESTORE URL HERE") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
let data = try! JSONDecoder().decode(Firebase.self, from: data!)
DispatchQueue.main.async {
completion(data.fields.goalsRoutines.arrayValue.values)
}
}.resume()
}
So this is how I currently get the data and show it on the app.
I am really lost on how to do the same on my Complication.
Any help is really appreciated.

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).