How to parse a stringified array in iOS Swift - swift

How to parse any stringified array such as "[\"Bob\", \"Tim\", \"Tina\"]" in Swift? It should return a JSON array such as ["Bob", "Tim", "Tina"].
Sorry if this is a duplicate question, but I could not find any answer for a generic stringified array where the structure of the array elements are not known.

Try doing it like this, Works for me every time:
let jsonText = "[\"Bob\", \"Tim\", \"Tina\"]"
var array: [String]?
if let data = jsonText.data(using: String.Encoding.utf8) {
do {
array = try JSONSerialization.jsonObject(with: data, options: []) as? [String]
if let myArray = array {
print(myArray)
}
} catch let error as NSError {
print(error)
}
}
It prints : ["Bob", "Tim", "Tina"]
Hope it helps!!

extension String
{
func decodeUrl() -> String
{
return self.removingPercentEncoding!
}
}
extension Data
{
func dataToJSON() -> Any? {
do {
return try JSONSerialization.jsonObject(with: self, options: [])
} catch let myJSONError {
print(myJSONError)
}
return nil
}
}
Usage :
if let data = your_stringified_array.decodeUrl().data(using: String.Encoding.utf8) {
if let jsonc = data.dataToJSON() {
print(jsonc)
}
}
Result is in AnyObject.

Related

How convert Realm data to Json on Swift? Realm version 10.11.0

until version 10.7.6 of Realm I could convert to dictionary and then to json with this code below, but the ListBase class no longer exists.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase { /*Cannot find type 'ListBase' in scope*/
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as! Object
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
let parameterDictionary = myRealmData.toDictionary()
guard let postData = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
List now inherits from RLMSwiftCollectionBase apparently, so you can check for that instead. Also, this is Swift. Use [String: Any] instead of NSDictionary.
extension Object {
func toDictionary() -> [String: Any] {
let properties = self.objectSchema.properties.map { $0.name }
var mutabledic = self.dictionaryWithValues(forKeys: properties)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic[prop.name] = nestedObject.toDictionary()
} else if let nestedListObject = self[prop.name] as? RLMSwiftCollectionBase {
var objects = [[String: Any]]()
for index in 0..<nestedListObject._rlmCollection.count {
let object = nestedListObject._rlmCollection[index] as! Object
objects.append(object.toDictionary())
}
mutabledic[prop.name] = objects
}
}
return mutabledic
}
}
Thanks to #Eduardo Dos Santos. Just do the following steps. You will be good to go.
Change ListBase to RLMSwiftCollectionBase
Change _rlmArray to _rlmCollection
Import Realm

How to retrieve value from Dict

I'm getting JSON format data from the server, then I convert the data format to the [String:Any].
JSON--> {
integer = 1;
length = "<null>";
object = (
"692b663b-b7d5-43-287ddaadc2ff"
);
string = "SANJEEV TREHAN";
}
Here is the code:
if let data = data{
do{
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let integer = json["integer"] as? Int {
DispatchQueue.main.async {
if integer == 1{
//retrieve data here
print(json)
}
else{
print("alert")
}
}
}
else{
print("no name")
}
}
after converting the data as [String: Any]:
json = `["length": <null>, "integer": 1, "string": SANJEEV TREHAN, "object": <__NSSingleObjectArrayI 0x2806acb10>(
692b663b-b7d5-43d5-daadc2ff) ]`
I want to retrieve the object key value from the json variable.
The data I want only is 692b663b-b7d54a-7dd-aadc2ff as the String
I tried many things but not getting the data which format I want.
Since you're using Swift, why not use Codable types instead? They're much easier to use and you don't have to do weird casting or testing everywhere.
struct Response: Codable {
let length: Int?
let integer: Int
let string: String
let object: SomeObject
}
struct SomeObject: Codable {
let uuid: UUID
}
do {
let response = try JSONDecoder().decode(Response.self, from: data)
} catch {
print(error)
}
Now you can now ask for the fields directly.
print(response.object.uuid)
Seems like your object key is an array of string. Here is how you can get the value.
if let yourObject = json["object"] as? [String] {
if yourObject.count != 0 {
yourObjectValue = yourObject[0]
}
}

iOS - Converting String to Double

So i am fetching from fire base config data and trying to manipulate it as so.
This is my struct :
struct FireBaseConfiguration: Codable {
var updateTime: String = ""
var iOSMinVersionForceUpdate: String = ""
var iOSMinVersionMessageUpdate: String = ""
var iOSMinFirmwareVersion: String = ""
var privacyPolicyUrlFireBase: String = ""
var termOfUseUrlFireBase: String = ""
}
This is my parser method:
func fireBaseConfigVersionMapParser(dataString: String, version: String) -> FireBaseConfiguration? {
var fireBaseConfiguration: FireBaseConfiguration?
let data = dataString.data(using: .utf8)!
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? NSDictionary {
let model = jsonArray.object(forKey: version)
let data = try JSONSerialization.data(withJSONObject: model!, options: .prettyPrinted)
do {
let parsedModel = try JSONDecoder().decode(FireBaseConfiguration.self, from: data)
print("parsedModel is: \(parsedModel)")
fireBaseConfiguration = parsedModel
} catch let error{
print(error)
}
} else {
print("bad json")
}
} catch let error{
print(error)
}
return fireBaseConfiguration
}
And this is the implementation in the vc:
self.remoteConfig?.fetch(withExpirationDuration: 0, completionHandler: { [unowned self] (status, error) in
if status == .success {
self.remoteConfig?.activateFetched()
guard let configVersionMap = self.remoteConfig?.configValue(forKey: "iOSConfigVersionMap").stringValue else { return }
if let configModel = self.parser.fireBaseConfigVersionMapParser(dataString: configVersionMap, version: self.getCurrentAppVersion()!) {
print(configModel)
print(configModel.iOSMinVersionForceUpdate)
print(configModel.iOSMinVersionMessageUpdate)
var doubleForceUpdate = Double(configModel.iOSMinVersionForceUpdate)
var doubleMessageUpdate = Double(configModel.iOSMinVersionMessageUpdate)
print(doubleForceUpdate)
print(doubleMessageUpdate)
}
} else {
print("Config not fetched")
print("Error: \(error?.localizedDescription ?? "No error available.")")
}
})
so the prints are so:
FireBaseConfiguration(updateTime: "13/7/2018", iOSMinVersionForceUpdate: "1.0.2", iOSMinVersionMessageUpdate: "1.0.2", iOSMinFirmwareVersion: "1.0.1", privacyPolicyUrlFireBase: "https://www.name.com/corporate/privacy-policy", termOfUseUrlFireBase: "https://www.name.com/corporate/terms-of-use")
1.0.2
1.0.2
nil
nil
any ideas?
It is a simple String, but it's not actually a valid Double (Double values do not have two decimal places). So this is why it is failing.
What I think you actually need is the ability to compare version numbers, there are a number of other answers on the site that can show you how to do this:
Compare two version strings in Swift
Compare version numbers in Objective-C
So you can just keep your version numbers as a String

How to search a JSON API and decode an array using AlamoFire

I am searching a JSON API and I need to decode an array inside of it. I am using AlamoFire. Example: When I type in the letter "F" I want only the "F" word to display. I would like to search only in the array "name". Any help on this would be greatly appreciated!
This is my code below:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let url = "http://dummy.com/url"
Alamofire.request(url).responseData { (dataResponse) in
if let err = dataResponse.error {
print("Failed to contact", err)
return
}
guard let data = dataResponse.data else { return }
let dummyString = String(data: data, encoding: .utf8)
print(dummyString ?? "")
do {
let searchResult = try JSONDecoder().decode(SearchResults.self, from: data)
print("Result Count:", searchResult.id)
} catch let decodeError {
print("Failed to decode:", decodeError)
}
}
}
struct SearchResults: Decodable {
let id: String
}
My API array looks like this:
{
resultId: "1",
name: "Food",
},
{
resultId: "2",
name: "Movies",
}
Your result is in array format so you need to put your model like this:
let searchResult = try JSONDecoder().decode([SearchResults].self, from: data)
And for search, you can apply filters:
let filteredArray = searchResult.filter( { $0.name.contains("f") } )
As you said, your response is:
[
{ resultId: "1", name: "Food" },
{ resultId: "2", name: "Movies"}
]
So, your struct would be,
struct SearchResults: Decodable {
let resultId: String
let name: String
}
And you will use it as:
do {
let resultArray = try JSONDecoder().decode([SearchResults].self, from: data)
print("Result Count:", searchResult.id)
} catch let decodeError {
print("Failed to decode:", decodeError)
}
For searching, you should use filter, as:
let searchString = "F"
let filteredArray = resultArray.filter( { String($0.name.first!) == searchString } )
For matching first character = String($0.name.first!) == searchText
Check if name has search Text = $0.name.contains(searchText)
In total:
do {
let searchResult = try JSONDecoder().decode([SearchResults].self, from: data)
let filteredArray = resultArray.filter( { $0.name.contains(searchText) } )
} catch let decodeError {
print("Failed to decode:", decodeError)
}

How to save an Array with Objects to UserDefaults

My Object conforms to the new Swift 4 Codeable protocol. How to save an array of these Objects in UserDefaults?
struct MyObject: Codeable {
var name: String
var something: [String]
}
myObjectsArray = [MyObject]() // filled with objects
UserDefaults.standard.set(myObjectsArray, forKey: "user_filters")
Error
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Attempt to insert non-property
list object
Whew, I got it working:
Here is the Swift 4 Syntax to save an Array with Codeable Objects:
My solution is to encode it as a JSON Object and save that:
static var getAllObjects: [MyObject] {
let defaultObject = MyObject(name: "My Object Name")
if let objects = UserDefaults.standard.value(forKey: "user_objects") as? Data {
let decoder = JSONDecoder()
if let objectsDecoded = try? decoder.decode(Array.self, from: objects) as [MyObject] {
return objectsDecoded
} else {
return [defaultObject]
}
} else {
return [defaultObject]
}
}
static func saveAllObjects(allObjects: [MyObject]) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(allObjects){
UserDefaults.standard.set(encoded, forKey: "user_objects")
}
}
You can use a more generic approach, using array with specific type:
(myObject = any custom codable object you like)
(myKey = a string constant key to be able to retrieve/set specific array)
//set
setObject(myArray, forKey: mykey)
//get
let myArray = getObject(forKey: mykey, castTo: Array<myObject>.self)
and generic functions also, for any type:
func setObject<Object>(_ object: Object, forKey: String) where Object: Encodable
{
let encoder = JSONEncoder()
do {
let data = try encoder.encode(object)
set(data, forKey: forKey)
synchronize()
} catch let encodeErr {
print("Failed to encode object:", encodeErr)
}
}
func getObject<Object>(forKey: String, castTo type: Object.Type) -> Object? where Object: Decodable
{
guard let data = data(forKey: forKey) else { return nil }
let decoder = JSONDecoder()
do {
let object = try decoder.decode(type, from: data)
return object
} catch let decodeError{
print("Failed to decode object:" , decodeError)
return nil
}
}