how I can call variable in mappable class from main view - json

I have three class one is the main view and here is the code of it
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getJSONS().getLowerJSON()
setupUI()
}
func setupUI(){
print(lowerData.companyName)
}
}
getsJSONS call an function that call almofire to handle json as in this code
class getJSONS {
func getLowerJSON(){
let URL = "http://tickerchart.com/interview/company-details.json"
Alamofire.request(URL).responseObject { (response: DataResponse<lowereViewResponse>) in
let lowereViewResponse = response.result.value
}
}
}
lowereViewResponse call the mappable class as in this code
class lowereViewResponse: NSObject, Mappable {
var companyName : String?
var symbol : String?
var tradesCount : Int?
var high : Int?
var low : Int?
var volume : Int?
var amount : Int?
override init() {
super.init()
}
convenience required init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
companyName <- map["company-name"]
symbol <- map["symbol"]
tradesCount <- map["trades-count"]
high <- map["high"]
low <- map["low"]
volume <- map["volume"]
}
required init?(map: Map){
companyName = ""
symbol = ""
tradesCount = 0
high = 0
low = 0
volume = 0
amount = 0
price = 0
}
}
all imports are done
I am trying to call class lowereViewResponse to access the variable but I get null when this is exited "print(lowerData.companyName)"

You can use like following:
let lowereViewObject: lowereViewResponse = Mapper< lowereViewResponse >().map(JSON: result)

Related

How to return gms location name from lat long swiftui

I have a place picker that gives me the location by searching the street name.
How I can retrieve the location name with this same class Placepicker just giving the lat long coordinates?
struct PlacePicker: UIViewControllerRepresentable {
func makeCoordinator() -> GooglePlacesCoordinator {
GooglePlacesCoordinator(self)
}
#Environment(\.presentationMode) var presentationMode
#Binding var address: String
#Binding var latitude: Double
#Binding var longitude: Double
func makeUIViewController(context: UIViewControllerRepresentableContext<PlacePicker>) -> GMSAutocompleteViewController {
GMSPlacesClient.provideAPIKey("xxxx")
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = context.coordinator
let fields: GMSPlaceField = GMSPlaceField(rawValue:UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue) |
UInt(GMSPlaceField.coordinate.rawValue) |
GMSPlaceField.addressComponents.rawValue |
GMSPlaceField.formattedAddress.rawValue)
autocompleteController.placeFields = fields
let filter = GMSAutocompleteFilter()
filter.type = .address
autocompleteController.autocompleteFilter = filter
return autocompleteController
}
func updateUIViewController(_ uiViewController: GMSAutocompleteViewController, context: UIViewControllerRepresentableContext<PlacePicker>) {
}
class GooglePlacesCoordinator: NSObject, UINavigationControllerDelegate, GMSAutocompleteViewControllerDelegate {
var parent: PlacePicker
init(_ parent: PlacePicker) {
self.parent = parent
}
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
DispatchQueue.main.async {
print(place.description.description as Any)
self.parent.address = place.formattedAddress ?? "adresa gresita"
self.parent.presentationMode.wrappedValue.dismiss()
self.parent.latitude=place.coordinate.latitude
self.parent.longitude=place.coordinate.longitude
}
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
print("Error: ", error.localizedDescription)
}
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
parent.presentationMode.wrappedValue.dismiss()
}
}
}
How can I add a function like, giveLocationByLatLong(lat: Double, long: Double)?
Or can I use some stuff from the place picker class?

Parsing JSON & work with ObjectMapper,SwiftRealm,ObjectMapperAdditions,ObjectMapperAdditionsRealm & Alamofire

regards, I am trying to serialize a json from the placeHolder page, the users one (https://jsonplaceholder.typicode.com/ users), I am trying to use the following libraries together:
-> Alamofire
-> RealmSwift
-> ObjectMapper
-> ObjectMapperAdditions
-> ObjectMapper_Realm
Here is the model that I am defining, but the problem is that SwiftRealm does not support the ArrayDictionary data type, as you try changing the type in the COMPANY & ADDRESS attributes, which are of the array type, try to put it as List , [Address1]?, Address1, List , etc. but it does not work, it always marks the same error "The operation could not be completed, ObjectMapper could not serialize the response.", so it can be received as an object but it can not be saved in RealmSwift or failing that What to do, but you will also receive as JSON or ARRAY and it is also not possible to serialize it, have you implemented something like that?
import Foundation
import RealmSwift
import ObjectMapper
import ObjectMapperAdditions
import ObjectMapper_Realm
class PlaceHolderClass: Object, Mappable {
#objc dynamic var id = 0
#objc dynamic var name = ""
#objc dynamic var username = ""
#objc dynamic var email = ""
var address: Address1?
#objc dynamic var phone = ""
#objc dynamic var website = ""
var company: Company?
required convenience init?(map: Map) {
self.init()
}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
username <- map["username"]
email <- map["email"]
address <- map["address"]
phone <- map["phone"]
website <- map["website"]
company <- map["company"]
}
}
class Address1: Object, Mappable {
var street = List<String>()
var suite = List<String>()
var city = List<String>()
var zipcode = List<String>()
var geo: Geo?
required convenience init?(map: Map) {
self.init()
}
func mapping(map: Map) {
street <- map["street"]
suite <- map["suite"]
city <- map["city"]
zipcode <- map["zipcode"]
geo <- map["geo"]
}
}
class Geo: Object, Mappable {
var lat = List<String>()
var lng = List<String>()
required convenience init?(map: Map) {
self.init()
}
func mapping(map: Map) {
lat <- map["lat"]
lng <- map["lng"]
}
}
class Company: Object, Mappable {
var name = List<String>()
var catchPhrase = List<String>()
var bs = List<String>()
required convenience init?(map: Map) {
self.init()
}
func mapping(map: Map) {
name <- map["name"]
catchPhrase <- map["catchPhrase"]
bs <- map["bs"]
}
}
My request Code:
func requestPlaceHolder(){
let URL = "https://jsonplaceholder.typicode.com/users"
Alamofire.request(URL).responseObject{ (response: DataResponse<PlaceHolderClass>) in
switch response.result {
case .success(let objects):
let realm = try! Realm()
let myPlaceHolderResponse = PlaceHolderClass(value: response.result.value)
try! realm.write {
realm.add(myPlaceHolderResponse, update: true)
print("se agrego correctamente")
}
print(Realm.Configuration.defaultConfiguration.fileURL)
case .failure(let error):
print("Ocurrio el siguiente error \(error.localizedDescription)")
}
print(Realm.Configuration.defaultConfiguration.fileURL)
}
}

How to map different type using ObjectMapper?

I'm using ObjectMapper to map my JSON to Swift object.
I have the following Swift object:
class User: Mappable {
var name: String?
var val: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
val <- map["userId"]
}
}
I have this JSON structure:
{
"name": "first",
"userId": "1" // here is `String` type.
},
{
"name": "second",
"userId": 1 // here is `Int` type.
}
After mapping the JSON, the userId of User which name is "first" is null.
How can I map Int/String to Int?
After reading the code of ObjectMapper, I found an easier way to solve the problem, it's to custom the transform.
public class IntTransform: TransformType {
public typealias Object = Int
public typealias JSON = Any?
public init() {}
public func transformFromJSON(_ value: Any?) -> Int? {
var result: Int?
guard let json = value else {
return result
}
if json is Int {
result = (json as! Int)
}
if json is String {
result = Int(json as! String)
}
return result
}
public func transformToJSON(_ value: Int?) -> Any?? {
guard let object = value else {
return nil
}
return String(object)
}
}
then, use the custom transform to the mapping function.
class User: Mappable {
var name: String?
var userId: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
userId <- (map["userId"], IntTransform()) // here use the custom transform.
}
}
Hope it can help others who have the same problem. :)
If your API is like this - it is very bad API. What you could do is have two variables instead of one:
class User: Mappable {
var name: String?
var valInt: Int?
var valString: String?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
valInt <- map["val"]
valString <- map["val"]
}
}
You can even add function that will get you value like:
// bellow func mapping(map: Map){
func getUserId() -> String {
if(self.valInt != nil) {
return "\(valInt!)"
}
else {
return valString!
}
}
Or, using if let:
func getUserId() -> String {
if let userId = self.valInt {
return "\(userId)"
}
if let userId = valString {
return userId
}
return ""
}
Or using optionals so later on you can use if let userId = object.getUserId()
func getUserId() -> String? {
if(self.valInt != nil) {
return String(valInt)
}
else {
return valString
}
}
You should improve your API. However, if you can't do that, then try this code:
class User: Mappable {
var name: String?
var val: Int?
required init?(map: Map) { }
func mapping(map: Map) {
name <- map["name"]
// 1: Get the value of JSON and store it in a variable of type Any?
var userIdData: Any?
userIdData <- map["userId"]
// 2: Check the value type of the value and convert to Int type
if userIdData is Int {
val = (userIdData as! Int)
} else if userIdData is String {
val = Int(userIdData as! String)
}
}
}
You can refer to this document: Type Casting

Swift use ObjectMapper with singleton

I want use ObjectMapper to parsing Json string within a singleton situation. Example code :
class User: Mappable {
var username: String?
var signature: String?
//Singleton
static let shared = User()
private init() {}
//Mappable functions
required init?(map: Map) {}
func mapping(map: Map) {
username <- map["username"]
signature <- map["signature"]
}
//Update userInfo after network request
func getUserInfo() {
//Network things
...
//Example data
let data = [
"username": "Eason",
"signature": "I love U"
]
//Some thing like this to update userInfo
Mapper<User>().map(data)
}
}
So, what is the right way to use ObjectMapper in singleton situation?
I prefer the following option.
1) UserManager (singleton):
class UserManager: NSObject {
static let shared = UserManager()
var profile: UserProfile?
private override init() {}
func loadUserProfile(completion: #escaping () -> ()) {
RestClient.shared.getUserProfile() { [weak self] (profile, error) in
guard let `self` = self else { return }
self.profile = profile as? UserProfile
completion()
}
}
}
2) User model:
class UserProfile: Mappable {
var username: String?
var signature: String?
required init?() {}
required init?(map: Map) {}
func mapping(map: Map) {
username <- map ["username"]
signature <- map ["signature"]
}
}
3) RestClient
typealias IdResponseBlock = (_ swiftObj: Any?, _ error: Error?) -> Void
class RestClient: NSObject {
static let shared = RestClient()
// Additional class where sending and receiving information from the server occurs
private var http = HttpService()
let baseUrl = ApiSettings.shared.kServerBaseURL
override init() {
super.init()
}
func parseData<P: BaseMappable>(object: Any, modelCls: P.Type, response: (IdResponseBlock)) {
if object is NSArray {
let result = Mapper<P>().mapArray(JSONObject: object)
return response(result, nil)
}
if object is NSDictionary {
let model: P = Mapper<P>().map(JSONObject: object)!
return response(model, nil)
}
}
//MARK: - API
//MARK: - User
func getUserProfile(resp: #escaping IdResponseBlock) {
let url = baseUrl + Requests.profile
http.queryBy(url, method: .get, queue: .background, resp: { (response, error) in
if let err = error {
return resp(nil, err)
}
guard let data = response else {
return resp(nil, error)
}
let jsonData = JSON(data)["data"]
self.parseData(object: jsonData.rawValue,
modelCls: UserProfile.self,
response: resp)
})
}
}

unexpectedly found nil while unwrapping an Optional value for my UITextField

I'm having trouble passing the JSON values (I'm reading successfully) into my textfield on the next viewcontroller because of this unwrapping error, stating my text field is nil.
I'm very stuck. Here's my class that reads the JSON:
class DoOAuth
{
func doOAuthFitbit() -> String{
var name = ""
let oauthswift = OAuth1Swift(
consumerKey: "eabf603efe9e45168d057b60b03f8e94",
consumerSecret: "46b4dfa8c9d59666769e03f887d531a8",
requestTokenUrl: "https://api.fitbit.com/oauth/request_token",
authorizeUrl: "https://www.fitbit.com/oauth/authorize?display=touch",
accessTokenUrl: "https://api.fitbit.com/oauth/access_token")
oauthswift.authorizeWithCallbackURL( NSURL(string: "fitbit://oauth")!,
success:{
credential, response in
let vc: ViewController = ViewController()
let user: OAuthSwiftClient = OAuthSwiftClient(consumerKey: oauthswift.consumer_key, consumerSecret: oauthswift.consumer_secret, accessToken: credential.oauth_token, accessTokenSecret: credential.oauth_token_secret)
let object:[String : AnyObject] = ["oauth_token": credential.oauth_token, "oauth_token_secret" : credential.oauth_token_secret]
user.get("https://api.fitbit.com/1/user/-/profile.json", parameters: object,
success: {
(data: NSData, response: NSHTTPURLResponse) -> Void in
let jsonValues = JSON(data: data, options: NSJSONReadingOptions.AllowFragments, error: nil)
println(jsonValues)
/*public var dictionary: [Swift.String: JSON]?
{
switch self
{
case .Dictionary(let d):
var jsonObject: [Swift.String: JSON] = [:]
for(k,v) in d
{
jsonObject[k] = JSON.wrap(v)
}
return jsonObject
default:
return nil
}
}*/
for(key, subJson) in jsonValues
{
if let nm = subJson["fullName"].string
{
println("\(nm)")
name = nm
}
}
/*for(index: String, subJson: JSON) in jsonValues
{
let name = subJson.dictionary?["fullName"]?.string
println("\(name!)")
//vc.nm.text = name!
main.acceptJson(name!)
}*/
},
failure: {
(error:NSError!) -> Void in
println(error.localizedDescription)
println("error")
})
},
failure: {
(error:NSError!) -> Void in
println(error.localizedDescription)
})
return name
}
}
I call a function that is supposed to receive the JSON strings (acceptJson) located in the next view controller:
class mainMenu: UIViewController
{
var oauthfitbit: DoOAuth = DoOAuth()
var name = ""
//let vc: ViewController = ViewController()
#IBOutlet weak var lbl: UILabel!
#IBOutlet weak var nameField: UITextField!{
didSet{
nameField.text = name
}
}
override func viewWillAppear(animated: Bool)
{
//name = oauthfitbit.doOAuthFitbit()
//self.nameField.text = "Working"
//self.nameField.text = name
}
func acceptJson(info: String!)
{
println("\(info)")
self.nameField.text = info
//name = info
}
}
I get the excepting thrown on the setting nameField.text line stating nameField is nil. How do I get the textfield to store the JSON string?
And here's the initial View Controller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var nm: UITextField!
//let main: mainMenu = mainMenu()
var name = ""
#IBAction func connectPressed(sender: UIButton)
{
var oauthFitbit: DoOAuth = DoOAuth()
name = oauthFitbit.doOAuthFitbit()
self.performSegueWithIdentifier("loginSuccess", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "loginSuccess")
{
let controller = segue.destinationViewController as! mainMenu
controller.name = name
//vc.nameField.text = "Hello"
}
}
}
How did you create your textfield? Was it through Interface Builder? There have been plenty of times when I've run into these type of problems when using Interface Builder and IBOutlets.
The first step is to make sure your text field is connected to your view controller from the .xib file correctly. Delete the connection and reconnect by control (command?) dragging from IB to your view controller code.
If you're not using IB and still having problems, post the code where you create the textfield. You have to set your view controller as the text field delegate if you're creating it programmatically, I believe. It's been awhile since I've done it that way.
Let us know!
The easiest way to get the new view controller the value of nm is in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourIdentifier" {
let controller = segue.destinationViewController as! mainMenu
controller.name = name
}
}
So, to get this to work, you will need to add a name instance variable (var name = "") to your first view controller, and change main.acceptJson(nm) to name = nm.
Once name is set in your first view controller, you can segue to the second view controller.
In the second view controller, you can change your text field outlet to this:
#IBOutlet weak var nameField: UITextField! {
didSet {
nameField.text = name
}
}
The didSet is a property observer. You can't set the nameField text field directly from the first view controller's prepareForSegue because the text field isn't set up yet when prepareForSegue is called in the first view controller. That's why you're storing it in an instance variable. Then, because of the didSet, your text field's text property will be set as soon as it comes into existence.
UPDATE:
The following is in a class of its own. Let's call that class DoOAuth (looks like that's what you called it):
class DoOAuth {
func doOAuthFitbit() -> String { // Now it's returning a string
var name = "" // Create local variable to return
let oauthswift = OAuth1Swift(
consumerKey: "eabf603efe9e45168d057b60b03f8e94",
consumerSecret: "46b4dfa8c9d59666769e03f887d531a8",
requestTokenUrl: "https://api.fitbit.com/oauth/request_token",
authorizeUrl: "https://www.fitbit.com/oauth/authorize?display=touch",
accessTokenUrl: "https://api.fitbit.com/oauth/access_token")
oauthswift.authorizeWithCallbackURL( NSURL(string: "fitbit://oauth")!,
success:{
credential, response in
//let vc: ViewController = ViewController() // Get rid of this
let user: OAuthSwiftClient = OAuthSwiftClient(consumerKey: oauthswift.consumer_key, consumerSecret: oauthswift.consumer_secret, accessToken: credential.oauth_token, accessTokenSecret: credential.oauth_token_secret)
let object:[String : AnyObject] = ["oauth_token": credential.oauth_token, "oauth_token_secret" : credential.oauth_token_secret]
user.get("https://api.fitbit.com/1/user/-/profile.json", parameters: object,
success: {
(data: NSData, response: NSHTTPURLResponse) -> Void in
let jsonValues = JSON(data: data, options: NSJSONReadingOptions.AllowFragments, error: nil)
println(jsonValues)
/*public var dictionary: [Swift.String: JSON]?
{
switch self
{
case .Dictionary(let d):
var jsonObject: [Swift.String: JSON] = [:]
for(k,v) in d
{
jsonObject[k] = JSON.wrap(v)
}
return jsonObject
default:
return nil
}
}*/
for(key, subJson) in jsonValues
{
if let nm = subJson["fullName"].string
{
println("\(nm)")
name = nm // Store 'nm' in local variable declared above
}
}
}
return name
} // end doOAuthFitbit()
} // end class
Now change your connectPressed() method in ViewController to this:
#IBAction func connectPressed(sender: UIButton)
{
var oauthFitbit: DoOAuth = DoOAuth()
name = oauthFitbit.doOAuthFitbit() // doOAuthFitbit() now returns a String
self.performSegueWithIdentifier("loginSuccess", sender: nil)
}
Now it should work.