I created a struct UserModel.swift to store the json data:-
struct UserModel {
var id: Int = 0
var uuid:Int = 0
var user_name: String = ""
var password: String = ""
var name: String = ""
var email: String = ""
init(json: [String:Any]) {
if let obj = json["id"] as? Int {
self.id = obj
}
if let obj = json["uuid"] as? Int {
self.uuid = obj
}
if let obj = json["user_name"] as? String {
self.user_name = obj
}
if let obj = json["name"] as? String {
self.name = obj
}
if let obj = json["email"] as? String {
self.email = obj
}
}
}
Now I used Alamofire to get the json in my ViewController.Swift file and I stored my struct by creating a variable I am successfully get the json and stored it in my struct.
var userModel = [UserModel]()
private func getList() {
progressHUD.show(in: view, animated: true)
// let uuid = UserDefaults.standard.integer(forKey: "uuid")
Alamofire.request(Constants.API.url("list_request?device_token=\(device_token ?? "")&uuid=794849"), method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON {
(response:DataResponse<Any>) in
self.progressHUD.dismiss()
guard let json = response.result.value as? [String:Any] else {return}
guard let data = json["data"] as? [[String:Any]] else {return}
printD(data)
guard let status = json["status"] as? Bool else { return}
printD(status)
if status == true {
guard let data = json["data"] as? [[String:Any]] else {return}
for userData in data {
self.userModel.append(UserModel(json: userData))
printD(self.userModel)
}
CommonClass.shared.showSuccessMessage("\(json["msg"] as? String ?? "")", inViewController: self)
}
else if status == false {
CommonClass.shared.showErrorMessage("\(json["msg"] as? String ?? "")", inViewController: self)
}
else {
CommonClass.shared.showErrorMessage("Server Connection Error. Please try again later", inViewController: self)
}
self.tableView.reloadData()
}
}
Now the problem I am getting I have to use my userModel data in another api in same class and I don't know How Can I do that. In rejectRequest() function I need to access some of my struct data but I don't know how can I do that. Please help?
private func rejectRequest() {
let user = userModel // I need to use userModel data for parameter
let param: [String:Any] = ["from_user": "", "to_user": "", "request_id": "", "device_token": device_token ?? ""]
Alamofire.request(Constants.API.url("end_request"), method: .post, parameters: param, encoding: JSONEncoding.default, headers: nil).responseJSON {
(response:DataResponse<Any>) in
}
}
Create a struct to hold common data that is shared across the app. Here's a sample for a DataController that can hold different models or arrays / dicts of models:
struct DataController {
// MARK: - User management
struct Users {
static var users: [User] = []
static var currentUser: User = User()
static func addUser(_ user: User) {
users.append(user)
}
static func findUserById(_ id: Int) -> User? {
// Find the users that match the id (should only be one!)
let users = user.filter { $0.id = id }
return users.count == 1 ? users[0] : nil
}
}
}
Add a user:
DataController.Users.addUser(user)
Access from elsewhere by:
DataController.Users.currentUser
Find a user by an id:
if let user = DataController.Users.findUserById(id) {
... do stuff ...
}
Incidentally, might be simpler to use a guard statement when parsing your JSON data:
init(json: [String:Any]) {
guard
let id = json["id"] as? Int,
let uuid = json["uuid"] as? Int,
let user_name = json["user_name"] as? String,
let name = json["name"] as? String,
let email = json["email"] as? String
else {
return // Fail
}
self.id = id
self.uuid = uuid
self.user_name = user_name
self.name = name
self.email = email
}
Related
I'm having a hard time trying to retrieve both the postId and commentId at the same time.
The goal is to allow a user to delete their own comment on a post.
Here is the Comment Struct, below is a the function that should delete the users comment, however for some reason I can only return the commentId and not the postId. So the comment is not deleted when clicked.
The postId will = nil if I run a break point in the final like of deleteComment, but if I run a break point on the final line of func fetchComment the postId will return whatever the postId is for the post.
struct Comment {
var commentId: String!
let user: User
var creationDate: Date!
let text: String
let uid: String!
init(commentId: String!,user: User, dictionary: [String: Any]) {
self.commentId = commentId
self.user = user
self.text = dictionary["text"] as? String ?? ""
self.uid = dictionary["uid"] as? String ?? ""
if let creationDate = dictionary["creationDate"] as? Double {
self.creationDate = Date(timeIntervalSince1970: creationDate)
}
}
var post: Post?
func deleteComment() {
guard let postId = self.post?.postId else { return }
guard let commentId = self.commentId else { return }
let commentsRef = Database.database().reference().child("comments")
commentsRef.child(postId).child(commentId).removeValue()
}
Here is how comments are fetched
var comments = [Comment]()
func fetchComments() {
guard let postId = self.post?.postId else { return }
let ref = Database.database().reference().child("comments").child(postId)
ref.observe(.childAdded, with: { (snapshot) in
let commentId = snapshot.key
//print(commentId)
guard let dictionary = snapshot.value as? [String: Any] else { return }
guard let uid = dictionary["uid"] as? String else { return }
Database.fetchUserWithUID(with: uid, completion: { (user) in
let comment = Comment(commentId: commentId, user: user, dictionary: dictionary)
self.comments.append(comment)
self.collectionView?.reloadData()
})
}) { (err) in
print("Failed to observe comments")
}
}
Also, here is the code when users submit a comment
func didSubmit(for comment: String) {
guard let uid = Auth.auth().currentUser?.uid else { return }
print("post id:", self.post?.postId ?? "")
print("Inserting comment:", comment)
let postId = self.post?.postId ?? ""
let values = ["text": comment, "creationDate": Date().timeIntervalSince1970, "uid": uid] as [String : Any]
Database.database().reference().child("comments").child(postId).childByAutoId().updateChildValues(values) { (err, ref) in
if let err = err {
print("Failed to insert comment:", err)
return
}
self.uploadCommentNotificationToServer()
if comment.contains("#") {
self.uploadMentionNotification(forPostId: postId, withText: comment, isForComment: true)
}
self.containerView.clearCommentTextView()
}
}
Json for comments via firebase
"comments" : {
"-Lord0UWPkh5YdGIHtAO" : {
"-Lp7AQzHccme5RcRsyDd" : {
"creationDate" : 1.568874020882821E9,
"text" : "Wow Cool!",
"uid" : "wELwYnMGxxW0LJNRKBuuE2BUaV93"
}
},
"-LowvCk-agvJbK0VF-Bq" : {
"-LpKm1NcgOsXhwj6soxE" : {
"creationDate" : 1.569102243436777E9,
"text" : "Nice!",
"uid" : "wELwYnMGxxW0LJNRKBuuE2BUaV93"
},
One option is to make postId a property in the Comment struct and add it to the init method, this way you will always has access to it
struct Comment {
let postId: String
var commentId: String!
let user: User
var creationDate: Date!
let text: String
let uid: String!
init(commentId: String!,user: User, postIdentifier: String, dictionary: [String: Any]) {
self.commentId = commentId
self.user = user
self.postId = postIdentifier
...
I'm querying some data from my firestore,and I put it in my Usersdata,
but I dont know how to get my values from Usersdata.
Please help me to query my data!
This is my struct base on Firestroe example
struct Usersdata {
let uid:String?
let facebook:String?
let google:String?
let name:String?
let age:Int?
let birthday:String?
let smokeage:Int?
let smokeaddiction:Int?
let smokebrand:String?
let gold:Int?
let score:Int?
let fish:Int?
let shit:Int?
let userimage:String?
init?(dictionary: [String: Any]) {
guard let uid = dictionary["uid"] as? String else { return nil }
self.uid = uid
self.facebook = dictionary["facebook"] as? String
self.google = dictionary["google"] as? String
self.name = dictionary["name"] as? String
self.age = dictionary["age"] as? Int
self.birthday = dictionary["birthday"] as? String
self.smokeage = dictionary["smokeage"] as? Int
self.smokeaddiction = dictionary["smokeaddiction"] as? Int
self.smokebrand = dictionary["smokebrand"] as? String
self.gold = dictionary["gold"] as? Int
self.score = dictionary["score"] as? Int
self.fish = dictionary["fish"] as? Int
self.shit = dictionary["shit"] as? Int
self.userimage = dictionary["userimage"] as? String
}
}
this is my function to query data from firebase
func test(schema:String , collection:String , document : String){
let queryRef = db.collection("Users").document(userID).collection(collection).document(document)
queryRef.getDocument { (document, error) in
if let user = document.flatMap({
$0.data().flatMap({ (data) in
return Usersdata(dictionary: data)
})
}) {
print("Success \(user)")
} else {
print("Document does not exist")
}
}
}
I think you are asking how to work with a structure with Firebase data. Here's a solution that will read in a known user, populate a structure with that data and then print the uid and name.
Assume a stucture
Users
uid_0
name: "Henry"
and then a structure to hold that data
struct Usersdata {
let uid:String?
let user_name:String?
init(aDoc: DocumentSnapshot) {
self.uid = aDoc.documentID
self.user_name = aDoc.get("name") as? String ?? ""
}
}
and a function to read that user, populate the struct and print out data from the struct
func readAUser() {
let docRef = self.db.collection("Users").document("uid_0")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let aUser = Usersdata(aDoc: document)
print(aUser.uid, aUser.user_name)
} else {
print("Document does not exist")
}
}
}
and the output
uid_0 Henry
I am new in using Swift I created an APIService using Alamofire, I tried to check whether I can retrieve data from API and it turn out well. My problem now, how can the data reflect to the variables in my Event Struct, so I could perform some validation base on the data read. I tried to check thru breakpoint but variable can't read data or either " " value. Please help me. Thank you
Event Struct
struct Event: Codable {
let id: String?
let name: String
let location: String
let startDateTime: Date
let endDateTime: String
let deleteFlag: Bool?
let deleteDateTime: String?
let dateCreated: String?
let hasRaffle: Bool?
let registrationReq: Bool?
let participantCount: Int
let closedFlag: Bool?
let closedDateTime: String?
let reopenFlag: Bool?
let reopenDateTime: String?
init?(JSON: [String: AnyObject]) {
guard let eventID = JSON["event_id"] as? String,
let eventName = JSON["event_name"] as? String,
let eventLocation = JSON["event_location"] as? String,
let startDateTime = JSON["start_datetime"] as? String,
let endDateTime = JSON["end_datetime"] as? String,
let participantCount = JSON["participant_count"] as? Int else {
return nil
}
self.id = eventID
self.name = eventName
self.location = eventLocation
self.endDateTime = endDateTime
self.participantCount = participantCount
if let formattedStartDateTime = getDateFromString(dateString: startDateTime, formatString: "yyyy-MM-dd'T'HH:mm:ss.SSS") {
self.startDateTime = formattedStartDateTime
}else {
self.startDateTime = Date()
}
if let deleteFlag = JSON["delete_flag"] as? Bool {
self.deleteFlag = deleteFlag
}else {
self.deleteFlag = nil
}
if let deletedDateTime = JSON["deleted_datetime"] as? String {
self.deleteDateTime = deletedDateTime
}else {
self.deleteDateTime = nil
}
if let dateCreated = JSON["date_created"] as? String {
self.dateCreated = dateCreated
}else {
self.dateCreated = nil
}
if let hasRaffle = JSON["hasRaffle"] as? Bool {
self.hasRaffle = hasRaffle
}else {
self.hasRaffle = nil
}
if let registrationReq = JSON["registration_req"] as? Bool {
self.registrationReq = registrationReq
}else {
self.registrationReq = nil
}
if let closedFlag = JSON["closed_flag"] as? Bool {
self.closedFlag = closedFlag
}else {
self.closedFlag = nil
}
if let closedDateTime = JSON["closed_datetime"] as? String {
self.closedDateTime = closedDateTime
}else {
self.closedDateTime = nil
}
if let reopenFlag = JSON["reopen_flag"] as? Bool {
self.reopenFlag = reopenFlag
}else {
self.reopenFlag = nil
}
if let reopenDateTime = JSON["reopen_datetime"] as? String {
self.reopenDateTime = reopenDateTime
}else {
self.reopenDateTime = nil
}
}
}
APIService
class APIService
{
let eventAPIKey: String
let eventBaseURL: URL?
//static let kEventID = "id"
init(APIKey: String)
{
self.eventAPIKey = APIKey
eventBaseURL = URL(string: BASE_URL)
}
func validatePasscode(passcode: String, completion: #escaping (Event?) -> Void)
{
let passcodeURL = URL (string: "\(PASSCODE_CHECKER_URL)/\(passcode)")
Alamofire.request(passcodeURL!, method: .get).responseJSON { (response) in
switch response.result{
case .success:
if let passcodeJSON = response.result.value{
print(passcodeJSON)
completion(Event(JSON: json as [String : Any]))
}
case .failure(let error):
print("\(error)")
}
}
}
}
You need to try and initialize the Event struct with the data you received passcodeJSON. As you can see your Event initializer is init?(JSON: [String: AnyObject])
if let passcodeJSON = response.result.value{
// print(passcodeJSON)
completion(Event(JSON: passcodeJSON))
}
and where you call your API service:
apiServiceClient.validatePasscode(passcode: "testing") { eventDetails in
// do something with eventDetails here
}
Here I tried to parse the data from my local server but unable to parse it and it returning empty data and below are my model classes from which the data I was passing to an table view which can anyone help me what's wrong in implementing it?
Here I had attached my image which follows the Json format:
Code:
var homePageModel = [HomeBanner]()
func HomeBannerDownloadJsonWithURL(){
let url = URL(string: homePageUrl)!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil { print(error!); return }
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] {
for item in jsonObj {
print(item)
for dict in item {
print(dict)
let dict = HomeBanner(json: item)
self.homePageModel.append(dict!)
print(self.homePageModel)
}
}
print(self.homePageModel)
DispatchQueue.main.async {
self.homeTableView.delegate = self
self.homeTableView.dataSource = self
self.homeTableView.reloadData()
}
}
} catch {
print(error)
}
}
task.resume()
}
struct HomeBanner {
let title : String?
let titleInArabic : String?
let showTitle : String?
var banner = [ChildrenBanners]()
init?(json : [String:Any]) {
if let customAttribute = json["childran_banners"] as? [[String: AnyObject]] {
var result = [ChildrenBanners]()
for obj in customAttribute {
result.append(ChildrenBanners(json: obj as! [String : String])!)
}
self.banner = result
} else {
self.banner = [ChildrenBanners]()
}
self.title = json["title"] as? String ?? ""
print(self.title)
self.titleInArabic = json["title_in_arabic"] as? String ?? ""
self.showTitle = json["show_title"] as? String ?? ""
}
}
struct ChildrenBanners {
let bannerId : String?
let name : String?
let status : String?
let sliderId : String?
let desktopImage : String?
let mobileImage : String?
let imageAlt : String?
let sortOrder : String?
let startTime : String?
let endTime : String?
init?(json : [String:Any]) {
self.bannerId = json["banner_id"] as? String ?? ""
print(self.bannerId)
self.name = json["name"] as? String ?? ""
self.status = json["status"] as? String ?? ""
self.sliderId = json["slider_id"] as? String ?? ""
self.desktopImage = json["desktop_image"] as? String ?? ""
self.mobileImage = json["mobile_image"] as? String ?? ""
self.imageAlt = json["image_alt"] as? String ?? ""
self.sortOrder = json["sort_order"] as? String ?? ""
self.startTime = json["start_time"] as? String ?? ""
self.endTime = json["end_time"] as? String ?? ""
}
}
Just try these lines of code
if let jsonObj = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] {
self.homePageModel = jsonObj.map{HomeBanner(json: $0)}
print(self.homePageModel)
DispatchQueue.main.async {
self.homeTableView.delegate = self
self.homeTableView.dataSource = self
self.homeTableView.reloadData()
}
}
} catch {
print(error)
}
and there is no necessity of making optional initializer for HomeBanner and ChildrenBanners just use init(json : [String : Any]){} for both struct
Root of json is an array and then second level is dictionary with keys list1, list2 etc. You are missing that in your code. Should be something like this (I haven't compiled it).
if let data = data, let jsonObj = try JSONSerialization.jsonObject(with: data) as? [[String:[String:Any]]] {
for item in jsonObj {
for (_, dict) in item {
if let obj = HomeBanner(json: dict) {
self.homePageModel.append(obj)
}
}
}
}
There are lot of other issues in your code. Like force unwrapping optional. Using same parameters again within a scope. For example.
for dict in item {
let dict = HomeBanner(json: item)
// ....
}
You shouldn't use same param names like you are using dict it hides the scope of the outer dict.
I need to access the work data which is inside an array of dictionaries and I'm a little bit confuse with this. I'm using swift 3. Some one can give-me some piece of coding to make it done?
I'm using this
let work: NSArray! = fbData.value(forKey: "work") as! NSArray
if let position: NSArray = work[0] as! NSArray {
let positionName: String = position.value(forKey: "name") as! String
self.userWorkExpLabel.text = "\(positionName)" as String
}
but I'm having this answer:
Could not cast value of type '__NSDictionaryI' (0x1106c7288) to 'NSArray' (0x1106c6e28).
there's the API
{
"work": [
{
"employer": {
"id": "93643283467",
"name": "Oracast"
},
"location": {
"id": "111983945494775",
"name": "Calgary, Alberta"
},
"position": {
"id": "146883511988628",
"name": "Mobile Developer"
},
"start_date": "2017-04-30",
"id": "1446626725564198"
}
],
Ok guys. I tried what you posted and what I have now is something like this:
a structs class:
import Foundation
struct Worker{
let employer: Employer
let location: Location
let position: Position
let startDate:String
let id: String
init?(fromDict dict: Dictionary<String, Any>){
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>),
let location = Location(fromDict: dict["location"] as? Dictionary<String, String>),
let position = Position(fromDict: dict["position"] as? Dictionary<String, String>),
let startDate = dict["start_date"] as? String,
let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer{
let id: String
let name: String
init?(fromDict dict:Dictionary<String, String>?){
guard let id = dict?["id"],
let name = dict?["name"] else{
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Ive created a class called facebookGraphRequest.
import Foundation
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
class facebookGraphRequest: NSObject {
class func graphRequestWork(completion: #escaping(_ error: Error?, _ facebookUserWork: Worker)-> Void){
if ((FBSDKAccessToken.current()) != nil){
let parameters = ["fields": "name, picture.width(198).height(198), location{location}, work{employer}, education, about, id"]
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: parameters)
graphRequest.start { (connection, result, error) in
if ((error) != nil ){
print(error!)
}else {
print(result!)
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
}
}
}
}
}
and I'm calling this data inside the viewController with:
func facebookLogin(){
facebookGraphRequest.graphRequestWork { (error: Error?, facebookUserWork: Worker) in
self.userNameJobPositionLabel.text = "\(facebookUserWork.position)"
self.companyNameLabel.text = "\(facebookUserWork.employer)"
}
}
Somebody knows what's happening? There's nothing happening with the labels.
I thought this apis was easier than that. I'm really confused with this process... Sorry if it looks like stupid questions but I'm really messing my mind because of this things... I really need your help guys. My work depends on that :(
After experimenting with Swift 4 and going in the direction that #PuneetSharma demonstrated I found it's even easier when you use raw JSON text, Codable, and JSONDecoder:
import Foundation
// define the nested structures
struct Work: Codable {
let work: [Worker]
}
struct Worker: Codable {
let employer: Employer
let location: Location
let position: Position
let startDate: String
let id: String
// needed a custom key for start_date
enum CodingKeys : String, CodingKey {
case employer, location, position, startDate = "start_date", id
}
}
struct Employer: Codable {
let id: String
let name: String
}
struct Location: Codable {
let id: String
let name: String
}
struct Position: Codable {
let id: String
let name: String
}
// turn the text into `Data` and then
// decode as the outermost structure
if let jsonData = json.data(using: .utf8),
let work = try? JSONDecoder().decode(Work.self, from: jsonData) {
print(work)
}
The result is a Work structure with all the data:
Work(work: [
Model.Worker(employer : Model.Employer(id : "93643283467",
name: "Oracast"),
location : Model.Location(id : "111983945494775",
name: "Calgary, Alberta"),
position : Model.Position(id : "146883511988628",
name: "Mobile Developer"),
startDate: "2017-04-30",
id : "1446626725564198")
])
(I formatted the output a bit to clarify the structures produced.)
You get a lot of functionality for free just by using Codable. It's also simple to go the other way and produce JSON text from any of the structures.
You should ideally introduce model classes like this:
struct Worker {
let employer:Employer
let location:Location
let position:Position
let startDate:String
let id:String
init?(fromDict dict:Dictionary<String, Any>) {
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>), let location = Location(fromDict: dict["location"] as? Dictionary<String, String>), let position = Position(fromDict: dict["position"] as? Dictionary<String, String>), let startDate = dict["start_date"] as? String, let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Now, you can introduce a function like this:
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
Use this code
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let workArray = json["work"] as? [[String: Any]] {
if let dictWork = workArray.first {
if let dictPosition = dictWork["position"] as? [String: String] {
print("position name : \(dictPosition["name"])")
}
}
}
}