Parse JSON string to Model Object type Array - swift3

I got Encrypted data from API hit by below method
URLSession.shared.dataTask(with: url!)
converted data into JSON but still it is encrypted
var json = try(JSONSerialization.jsonObject(with: data!, options: .allowFragments))
converted it into string
let arr:String = json as! String
decrypted it
let jsonText = arr.fromBase64()//extension method, given end of question
now it is in Json Formate as below (this is only 1 record, there are more than 1 records in Json string)
{
"CompanyAlt_Key": 1,
"Company_Name": "XYZ LTD",
"TableName": "CompanyList"
},
I have a model of same type
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
}
here is fromBase64 method
func fromBase64() -> String {
let data = NSData.init(base64Encoded: self, options: []) ?? NSData()
return String(data: data as Data, encoding: String.Encoding.utf8) ?? ""
}
I am facing problem to get the Json String into an array of type CompanyList class
Help would be appreciate

You'll need to convert your jsonString to data first:
let jsonData = jsonString.data(using: .utf8)!
The convert the data to an array
let array = JSONSerialization.jsonObject(with: jsonData, options: nil) as? [[String: Any]]
Then iterate through the array…
let companies = array?.map {
return CompanyList(dictionary: $0)
}
Implement an init method for your CompanyList, passing in a dictionary for each record in your response…
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
init(dictionary: [String: Any]) {
companyAlt_Key = dictionary["companyAlt_Key"] as? Int
company_Name = dictionary["company_Name"] as? String
tableName = dictionary["tableName"] as? String
}
}
You can also use this to validate the data. If the fields in your class are non-optional, you can use an optional init as follows…
public class CompanyList {
public var companyAlt_Key : Int
public var company_Name : String
public var tableName : String
init?(dictionary: [String: Any]) {
guard let companyAlt_Key = dictionary["companyAlt_Key"] as? Int,
let company_Name = dictionary["company_Name"] as? String,
let tableName = dictionary["tableName"] as? String else {
return nil
}
self.companyAlt_Key = companyAlt_Key
self.company_Name = company_Name
self.tableName = tableName
}
}
If you're using an optional init, use flatMap to ensure you don't have any optional elements in your array…
let companies = array?.flatMap {
return CompanyList(dictionary: $0)
}

Related

Retrieving data from Firebase (Realtime Database) into a list (Kotlin)

The RealtimeDatabase structure in Firebase
I want to go over the entire users in "mifkada" and to add them into a list as a BlogPost object:
class BlogPost (
var namerv: String,
var gafrv: String,
var placerv: String,
var phonerv: String,
var notesrv: String
) {
constructor() : this("", "", "", "", "") {}
}
I tried to do it with a for loop but it doesn't work the way I wrote it
class DataSource{
companion object{
fun createDataSet(): ArrayList<BlogPost>{
var databaseMifkada = FirebaseDatabase.getInstance().getReference("mifkada")
val list = ArrayList<BlogPost>()
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot!!.exists()){
list.clear()
for (e in dataSnapshot.children){
val post = e.getValue(BlogPost::class.java)
list.add(post!!)
}
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
}
}
databaseMifkada.addValueEventListener(postListener)
return list
}
}
}
The values of your constructor does not match the names of your database values
class BlogPost (
var namerv: String,
var gafrv: String,
var placerv: String,
var phonerv: String,
var notesrv: String
) {
constructor() : this("", "", "", "", "") {}
}
Should be
class BlogPost (
var name: String,
var gaf: String,
var place: String,
var phone: String,
var notes: String
) {
constructor() : this("", "", "", "", "") {}
}
You need to have the same name because when you do
val post = e.getValue(BlogPost::class.java)
it will look for those field names under the reference, and if it can't be reached, you can't get those values

raw Value of optional type not unwrapped

I am trying to unwrap the raw value of an enum type in func toDictionary() , but I get an error.
How can I fix this?
enum ChatFeatureType: String {
case tenants
case leaseholders
case residents
}
class Chat {
var featureType: ChatFeatureType?
init(featureType: ChatFeatureType? = nil
self.featureType = featureType
}
//download data from firebase
init(dictionary : [String : Any]) {
featureType = ChatFeatureType(rawValue: dictionary["featureType"] as! String)!
}
func toDictionary() -> [String : Any] {
var someDict = [String : Any]()
// I get error on the line below: Value of optional type 'ChatFeatureType?' not unwrapped; did you mean to use '!' or '?'?
someDict["featureType"] = featureType.rawValue ?? ""
}
}
As featureType is an optional you have to add ? or ! as the error says
someDict["featureType"] = featureType?.rawValue ?? ""
But be aware that your code reliably crashes when you create an instance of Chat from a dictionary and the key does not exist because there is no case "".
Actually the purpose of an enum is that the value is always one of the cases. If you need an unspecified case add none or unknown or similar.
This is a safe version
enum ChatFeatureType: String {
case none, tenants, leaseholders, residents
}
class Chat {
var featureType: ChatFeatureType
init(featureType: ChatFeatureType = .none)
self.featureType = featureType
}
//download data from firebase
init(dictionary : [String : Any]) {
featureType = ChatFeatureType(rawValue: dictionary["featureType"] as? String) ?? .none
}
func toDictionary() -> [String : Any] {
var someDict = [String : Any]()
someDict["featureType"] = featureType.rawValue
return someDict
}
}

How we can pass default null value in parameter list of dictionary [String:String] while posting a request to server ? Swift3

In some case i have to post null values to server either as a default value or as a parameter's value.I tried many ways but it didnt work.I'm using Alamofire for posting a request.Please help.
Method-1
var empty : String = ""
let parameters = ["User-Id":userId,"search_cat": formattedArray ?? empty,"date1":ab ?? empty,"date2" : bc ?? empty,"docname" : empty
] as! [String : String]
Method-2
let parameters = ["User-Id":userId,"search_cat": formattedArray ?? "","date1":ab ?? "","date2" : bc ?? "","docname" : ""
] as! [String : String]
Method-3
var nullvalue : String = ""
if formattedArray == nil
{
formattedArray = ""
print(formattedArray)
}
if ab == nil
{
ab = ""
print(ab)
}
if bc == nil
{
bc = ""
print(bc)
}
if nullvalue == nil
{
nullvalue = ""
}
parameters = ["User-Id":userId,"search_cat": formattedArray,"date1":ab ,"date2" : bc ,"docname" : nullvalue ]
as! [String : String]
Method - 4 According to answer i changed parameterlist dictionary to [String:AnyObject] but still it's not working.And giving me the error.
var ab:String?
var bc : String?
var formattedArray: String?
parameters = ["User-Id":userId ,"search_cat": formattedArray ?? NSNull() ,
"date1":ab ?? NSNull() ,"date2" : bc ?? NSNull(),
"docname" : NSNull()] as! [String : AnyObject]
Method-4 giving me Error while trying to set formattedArray ?? NSNull() :
Cannot convert value of type 'NSNull' to expected argument type 'String'
with rest of the parameters its working fine.Please help.
UPDATED : is this that you want?
class RequestParameter : NSObject{
var formattedArray : String!
var date1 : String!
var date2 : String!
var docName : String!
var userId : String! // or whatever if hardCoded
func param() -> NSDictionary{
var param : [String : String] = [:]
param["User-Id"] = userId
param["search_cat"] = formattedArray
param["date1"] = date1
param["date2"] = date2
param["docname"] = docName
return param as! NSDictionary
}
}
You can call these parameters where ever required. like
var reqParam = RequestParameter()
reqParam.param()
I am really unaware of your Request parameter type. For eg. should it look like date1 = nil or something else.
This is all I could answer you. If wrong maybe someone might ans better.
Good Luck!!
I actually had the same issue a couple of days ago and solved it using NSNull().
When converting my class I want to send the videoUrl property regardless of it containing a value, so that the backend can update it in the DB.
dict["videoUrl"] = videoUrl ?? NSNull()
This will set the key "videoUrl" with the value of the property videoUrl, or if nil, an instance of NSNull().
Express.js then reads this as undefined and inserts a null value to the database.
EDIT: I saw one of your comments below. When using a Dictionary of type [String:String], you will never be able to pass a nil value.

parse json and saving into modelClass using JSonJoy in swift?

This is my json structure -----> How should I save in model Class using JSONJoy.
JSON:
Optional(<__NSSingleObjectArrayI 0x61000000b570>(
{
locationC = 116789;
locationN = testrtyuio;
siteName = lab;
}
)
)
Please check :
struct LocationDetails: JSONJoy {
var locationC: String? // based on your datatype change it
let locationN: String? // based on your datatype change it
let siteName: String? // based on your datatype change it
init(_ decoder: JSONDecoder) throws {
locationC = try decoder["locationC"].get()
locationN = try decoder["locationN"].get()
siteName = try decoder["siteName"].get()
}
}
let data = try Data(contentsOf: file) // data is your json format
var locationDetails = try LocationDetails(JSONDecoder(data))
print(locationDetails) // Output : LocationDetails(locationC: Optional("116789"), locationN: Optional("testrtyuio"), siteName: Optional("lab"))
print(locationDetails.locationC!) // Output : 116789

Getting ambiguous reference to member subscript

I am updating my code to swift3.0 but getting ambiguous refrence to member? What wrong i might be doing. Here is the method I am getting error in.
open class func parseJsonTenantList(_ list: [NSDictionary]?, strElementName: String, attrName1: String, attrNameValue2: String) -> [TenantRegister]
{
var renantList: [TenantRegister] = []
var key: String?
if let dict : [NSDictionary] = list {
var value: String?
for i in 0..<dict.count {
/// if attribute name doesn't match then it returns nil
if let s1: AnyObject = dict[i].value(forKey: attrName1)
{
key = s1 as? String
}
if let s2: AnyObject = dict[i].value(forKey: attrNameValue2)
{
value = s2 as? String
}
if (!(String.stringIsNilOrEmpty(value) && String.stringIsNilOrEmpty(key)))
{
let t: TenantRegister = TenantRegister()
t.name = key
t.tenantId = Guid(value!)
renantList.append(t)
}
}
}
return renantList
}
The issue is you are using NSDictionary, to solved your problem simply cast the list to Swift's native type [[String:Any]] and then use subscript with it instead of value(forKey:)
if let dict = list as? [[String:Any]] {
var value: String?
for i in 0..<dict.count {
/// if attribute name doesn't match then it returns nil
if let s1 = dict[i][attrName1] as? String
{
key = s1
}
if let s2 = dict[i][attrNameValue2] as? String
{
value = s2
}
if (!(String.stringIsNilOrEmpty(value) && String.stringIsNilOrEmpty(key)))
{
let t: TenantRegister = TenantRegister()
t.name = key
t.tenantId = Guid(value!)
renantList.append(t)
}
}
}
In Swift use native type Dictionary [:] and Array [] instead of NSDictionary and NSArray to overcome this type of issues.