Cannot convert value of type 'String?' (Alamofire) - swift

I map my class User with object mapper:
class User: Mappable{
private var _username: String! = nil
private var _password: String! = nil
private var _firstName: String! = nil
private var _lastName: String! = nil
//here are getters and setters(it takes too much space)
init(){
}
required init?(_ map: Map) {
}
func mapping(map: Map) {
username <- map["USERNAME"]
password <- map["PASSWORD"]
firstName <- map["FIRST_NAME"]
lastName <- map["LAST_NAME"]
}
}
And then i tried to make new user and put some values, map the whole object and send with Alamofire like this:
let userEmail = userEmailField.text!
let userPassword = userPasswordField.text!
let user = User()
user.username = userEmail
user.password = userPassword
let JSONString = Mapper().toJSONString(user, prettyPrint: true)
AlamofireService.alamofireService.makePostServiceRequest(URL_BASE, parameters: JSONString, resposeCallback: self)
I followed the instructions of libraries, but i get the error "Cannot convert value of type 'String?' to expected argument type '[String : AnyObject]'", why?

Alamofire request taking parameter in [String: AnyObject] format so you just need to pass dictionary as parameter. in your case you just need like:
let userEmail = userEmailField.text!
let userPassword = userPasswordField.text!
var dictParameter: Dictionary<String, AnyObject> = [:]
dictParameter["USERNAME"] = userEmail
dictParameter["PASSWORD"] = userPassword
And after that Just make request:
AlamofireService.alamofireService.makePostServiceRequest(URL_BASE, parameters: dictParameter, resposeCallback: self)

You don't need to covert your parameters to string, just pass parameters as dictionary to Alamofire.

Related

passing a struct type as a parameter throwing initialization error

I have the following code which has 3 objects which are then part of a 4th object. I'm getting errors trying to create the init method for the aggregate object (GTFS) because I'm passing (or trying to pass) the type of the 3 component objects (Stop, Route, Trip). I'm not sure why those have to be initialized before just their types being used.
protocol GTFSObject {
static var fileName: String { get }
init(csvRow: [String: String])
}
struct Stop: GTFSObject {
static let fileName = "stops.txt"
let stopID: String
let stopCode: String
let stopName: String
let stopDesc: String
let stopLat: Double
let stopLon: Double
let locationType: Int
let parentStation: String
init(csvRow: [String: String]) {
self.stopID = csvRow["stop_id"]!
self.stopCode = csvRow["stop_code"]!
self.stopName = csvRow["stop_name"]!
self.stopDesc = csvRow["stop_desc"]!
self.stopLat = Double(csvRow["stop_lat"]!)!
self.stopLon = Double(csvRow["stop_lon"]!)!
self.locationType = Int(csvRow["location_type"]!)!
self.parentStation = csvRow["parent_station"]!
}
}
struct Trip: GTFSObject {
static let fileName = "trips.txt"
let routeID: String
let serviceID: String
let tripID: String
init(csvRow: [String: String]) {
tripID = csvRow["trip_id"] ?? ""
routeID = csvRow["route_id"] ?? ""
serviceID = csvRow["service_id"] ?? ""
}
}
struct Route: GTFSObject {
static let fileName = "trips.txt"
let routeID: String
let agencyID: String
let routeShortName: String
let routeLongName: String
let routeDesc: String
let routeType: Int
let routeURL: String
let routeColor: String
let routeTextColor: String
init(csvRow: [String: String]) {
routeID = csvRow["route_id"] ?? ""
agencyID = csvRow["agency_id"] ?? ""
routeShortName = csvRow["route_short_name"] ?? ""
routeLongName = csvRow["route_long_name"] ?? ""
routeDesc = csvRow["route_desc"] ?? ""
routeType = Int(csvRow["route_type"] ?? "0") ?? 0
routeURL = csvRow["route_url"] ?? ""
routeColor = csvRow["route_color"] ?? ""
routeTextColor = csvRow["route_text_color"] ?? ""
}
}
class GTFS {
let routes: [Route]
let stops: [Stop]
let trips: [Trip]
init(gtfsFolderUrl: URL) {
self.stops = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
self.trips = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
self.routes = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
}
private func init_struct_from_url<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
var returnList: [GTFSType] = []
let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
for row in rows {
returnList.append(type.init(csvRow: row))
}
return returnList
}
}
The error I get is
'self' used in method call 'init_struct_from_url' before all stored properties are initialized
I don't know why I have to initialize the properties of the struct just to pass the type of the struct to this other function. What am I missing?
It's not about the three types that you are passing to init_struct_from_url. It's about the call init_struct_from_url itself.
You are actually calling:
self.init_struct_from_url(...)
^^^^^
The error is saying that that use of self is not allowed, because self is not initialised. If init_struct_from_url uses a property in self, it could see an uninitialised value.
Since init_struct_from_url doesn't actually use self at all and is just a helper function, you can make it an inner function of init:
init(gtfsFolderUrl: URL) {
func structFromUrl<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
var returnList: [GTFSType] = []
let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
for row in rows {
returnList.append(type.init(csvRow: row))
}
return returnList
}
self.stops = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
self.trips = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
self.routes = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
}

How should I retrieve data from firebase and put it into a dictionary?

I have an organization document with a Members collection inside of it and then a members document inside of that. Inside the members document includes a Map of a user which is a member. The Key is the UserID and 3 values (firstName, lastName, username). I am trying to load in this data into my "Event" class that holds a membersInvited Property that is a dictionary. Inside the Event class is a method to get this data called getOrgMembers(). Even though I have that data in firebase I am getting a nil value for my dictionary. I also am using Dispatch but kind of new to it.
Below is code in the Event Class:
var membersInvited: [Member: Bool]?
func getOrgMembers(dispatch: DispatchGroup?) {
let membRef = BandzDatabase.collection("Organizations").document(currentUser.currentOrgID!).collection("Members").document("members")
membRef.getDocument { (snapshot, error) in
if let error = error {
print (error.localizedDescription)
} else {
if let data = snapshot?.data() {
for (key,value) in data {
if let membArray = value as? [String: Any] {
let username = membArray["username"] as? String
let firstName = membArray["firstName"] as? String
let lastName = membArray["lastName"] as? String
let userID = key
let member = Member(username: username ?? "", firstName: firstName ?? "", lastName: lastName ?? "", userID: userID)
self.membersInvited?.updateValue(true, forKey: member)
}
}
}
}
dispatch?.leave()
}
}
struct Member: Hashable {
var username: String
var firstName: String
var lastName: String
var userID: String
init (username: String, firstName: String, lastName: String, userID: String) {
self.username = username
self.firstName = firstName
self.lastName = lastName
self.userID = userID
}
}
Below is were I call this method from another class:
func getMembers() {
showActivityIndicatory(uiView: self.view)
self.dispatchGroup.enter()
eventMade?.getOrgMembers(dispatch: self.dispatchGroup)
self.dispatchGroup.notify(queue: .main) {
//self.tableView.reloadData()
stopActivityIndicator()
print("happens")
print(self.eventMade?.membersInvited)
}
}
After some research, I discovered that since I never initilized the dictionary, whenever I was calling to append key-value paires it would not even run since it was an optional. So I changed the decleration to this:
var membersInvited: [Member: Bool] = [:]

Info.plist Dictionary to Dictionary of type Enum:String

I'm trying to take a dictionary from my Info.plist and save it as a Dictionary of type Enum: String
To better explain, I'm trying to convert the urlDict below to be a Dictionary of type but keep getting fatal error.
I can't figure out why
let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> does not work
The enum has a raw type of String and has a case for keyOne.
enum URLKeys: String {
case keyOne = "keyOne"
}
var keysDictionary = Dictionary<String, Any>()
keysDictionary["keyOne"] = "abc"
var urlDict = Dictionary<String, Any>()
urlDict["keys"] = keysDictionary
guard let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> else {
fatalError()
}
Use forEach and create a URLKeys for each key and cast each value to string
var enumDict:[URLKeys: String] = [:]
keysDictionary.forEach {
if let key = URLKeys(rawValue: $0.0), let value = $0.1 as? String {
enumDict[key] = value
}
}

How do I remove "Optional()" from object in an array

So im using CloudKit and fetching all the data into an array as [StartDay], my StartDay class looks like this:
import UIKit
import CloudKit
class StartDay {
var recordID: CKRecord.ID!
var wakeUp: String!
var sleptWell: String!
var dNN: String!
var created: String! {
get {
return created
}
}
}`
My function loads get an arraylist, which contains information received from the database. In my database it stands like this: "22.01.09:
func checkIfButtonShouldBeEnabled(startDayList: [StartDay]){
let startDayDates = startDayList.map{$0.created}
for i in 0..<startDayDates.count {
print(startDayDates)
}
}`
OUTPUT:
Optional("22.01.2019")
Optional("22.01.2019")
I want to remove "Optional()", so it only says "22.01.2019", how can I do so?
UPDATE: FETCH FUNC
func loadStartDay() -> [StartDay]{
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "StartDay", predicate: predicate)
let operation = CKQueryOperation(query: query)
var startDays: [StartDay] = []
operation.desiredKeys = ["wakeUp", "wellSlept", "dNN", "recordID", "createdDato"]
operation.recordFetchedBlock = { (record:CKRecord) in
let newStartDay = StartDay()
newStartDay.wakeUp = record.object(forKey: "wakeUP") as? String
newStartDay.sleptWell = record.object(forKey: "sleptWell") as? String
newStartDay.dNN = record.object(forKey: "dNN") as? String
newStartDay.recordID = record.object(forKey: "recordID") as? CKRecord.ID
newStartDay.created = record.object(forKey: "createdDato") as? String
print(newStartDay.created)
startDays.append(newStartDay)
}
You can use print(startDayDates!) or print(startDayDates ?? "default value").
But I recommend usage of startDayList.compactMap() instead of startDayList.map()to ensure your array doesn't contain nil values.
You can also do like this:
startDayList
.compactMap { $0.created }
.forEach { print($0) }
As you designed the database model you exactly know which record attributes always exist. Declaring class properties as implicit unwrapped optional as an alibi not to write an initializer is very bad practice.
Assuming every attribute in a record does have a value declare the properties as non-optional and write an initializer.
At least created and recordID are supposed to have always a value!
import UIKit
import CloudKit
class StartDay {
var recordID: CKRecord.ID
var wakeUp: String
var sleptWell: String
var dNN: String
var created: String
init(record : CKRecord) {
// recordID can be retrieved directly
self.recordID = record.recordID
self.wakeUp = record.object(forKey: "wakeUP") as! String
self.sleptWell = record.object(forKey: "sleptWell") as! String
self.dNN = record.object(forKey: "dNN") as! String
self.created = record.object(forKey: "createdDato") as! String
}
}
and create instances with
operation.recordFetchedBlock = { record in
startDays.append(StartDay(record: record))
}
Now the Optional has gone.
print(startDayList.map{ $0.created })

Reflection in swift 2

I have a class User:
import UIKit
import ObjectMapper
class User: NSObject, CustomStringConvertible, Mappable {
var FirstName: NSString! ;
var LastName: NSString! ;
required init?(_ map: Map){
}
func mapping(map: Map) {
FirstName <- map["FirstName"]
LastName <- map["LastName"]
}
override var description:String {
var s:String=""
//USE REFLECTION TO GET NAME AND VALUE OF DATA MEMBERS
for var index=1; index<reflect(self).count; ++index {
s += (reflect(self)[index].0 + ": "+reflect(self)[index].1.summary+"\t")
}
return s
}
}
In swift 1.2, I was using reflect() method to get array of all the data members with their names and values.
Now, after I have updated to swift 2, I am getting the following error:
'reflect' is unavailable: call the 'Mirror(reflecting:)' initializer
With some trials, I was able to get the count of data members by this: Int(Mirror(reflecting: self).children.count), but still, I am unable to get the member name and its value.
I have looked into the following resources:
https://netguru.co/blog/reflection-swift
http://nshipster.com/mirrortype/
UPDATE
I have found the an answer here: https://stackoverflow.com/a/32846514/4959077. But this doesn't tell how to find out the type of reflected value. If the value is int and we parse it into String then it gives error.
You may access the reflected attribute "label" name, value and type as follows:
let mirror = Mirror(reflecting: SomeObject)
var dictionary = [String: Any]()
for child in mirror.children {
guard let key = child.label else { continue }
let value: Any = child.value
dictionary[key] = value
switch value {
case is Int: print("integer = \(anyValue)")
case is String: print("string = \(anyValue)")
default: print("other type = \(anyValue)")
}
switch value {
case let i as Int: print("• integer = \(i)")
case let s as String: print("• string = \(s)")
default: print("• other type = \(anyValue)")
}
if let i = value as? Int {
print("•• integer = \(i)")
}
}
Note: per the question followup, three approaches to determine the type of the reflected value are shown.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}