how to pass multiple array data into a table view? - ios

here i am having two arrays in the url and i need to display as shown in image below and i don't know any idea how to implement this in table view as shown in image
{
"Flat": [
{
"price": "$5.00",
"id": 11,
"name": "Fixed"
}
],
"United Parcel Service": [
{
"price": "$109.12",
"id": 1,
"name": "worldwide Expedited"
},
{
"price": "$120.18",
"id": 2,
"name": "worldwide Express saver"
}
]
}
class shippingObject: NSObject {
var id :NSInteger!
var name :String!
var price : String!
}
class CheckoutViewController:
UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var ContinueButton: UIButton!
#IBOutlet weak var newAddress: UIButton!
#IBOutlet var tableDetails: UITableView!
#IBOutlet weak var shippingTableView: UITableView!
#IBOutlet weak var HeightConstraint: NSLayoutConstraint!
let url = "http://www.json-generator.com/api/json/get/bMlqRPbjGW?indent=2"
let urlString = "http://www.json-generator.com/api/json/get/bVWKKHtWbm?indent=2"
var detailsArray : [shippingObject] = []
var shippingArray :[[String: AnyObject]] = []
var price = [String]()
var keys = [String]()
var name = [String]()
var methodArray : [[String: AnyObject]] = []
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
var arrayss = [String:Any]()
var checkIsRadioSelect = [Int]()
var checkIsButtonEnable = [Int]()
var checkIsPaymentRadioSelect = [Int]()
let response : [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
tableDetails.isHidden = true
shippingTableView.isHidden = true
scrollView.isScrollEnabled = false
titleLabel.isHidden = true
newAddress.layer.cornerRadius = 5
ContinueButton.layer.cornerRadius = 5
myActivityIndicator.frame = CGRect(x: 130, y: 320, width: 30, height: 30)
myActivityIndicator.hidesWhenStopped = true
myActivityIndicator.startAnimating()
view.addSubview(myActivityIndicator)
myActivityIndicator.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: myActivityIndicator, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
view.addConstraint(horizontalConstraint)
let verticalConstraint = NSLayoutConstraint(item: myActivityIndicator, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0)
view.addConstraint(verticalConstraint)
self.shippingmethodURL()
self.shippingaddressURL()
tableDetails.delegate = self
tableDetails.dataSource = self
tableDetails.rowHeight = UITableViewAutomaticDimension
tableDetails.estimatedRowHeight = 300
shippingTableView.delegate = self
shippingTableView.dataSource = self
shippingTableView.rowHeight = UITableViewAutomaticDimension
shippingTableView.estimatedRowHeight = 300
// Do any additional setup after loading the view.
}
func shippingaddressURL() {
let url = NSURL(string: self.url)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
self.shippingArray = (jsonObj!.value(forKey: "address") as? [[String: AnyObject]])!
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
func assignValuesToObjecs(arrayvalues: NSArray){
(arrayvalues as NSArray).enumerateObjects({ (object, count, stop) in
let Object :shippingObject = shippingObject()
Object.name = (object as AnyObject) .value(forKey: "name") as! String
Object.id = (object as AnyObject) .value(forKey: "id") as! NSInteger
Object.price = (object as AnyObject).value(forKey: "price")as! String
self.detailsArray.append(Object)
})
}
func shippingmethodURL() {
let url = NSURL(string: self.urlString)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary { print(jsonObj!)
self.arrayss = jsonObj as! [String : Any]
print(self.arrayss)
//self.shippingArray = (jsonObj!.value(forKey: "Flat") as? [[String: AnyObject]])!
self.assignValuesToObjecs(arrayvalues :(jsonObj?["Flat"] as? [[String: AnyObject]]! as? NSArray)!)
self.assignValuesToObjecs(arrayvalues :(jsonObj?["United Parcel Service"] as? [[String: AnyObject]]! as? NSArray)!)
self.methodArray = (jsonObj!.value(forKey: "United Parcel Service") as? [[String: AnyObject]])!
OperationQueue.main.addOperation({
self.keys = ["Flat","United Parcel Service"]
self.shippingTableView.reloadData()
})
}
}).resume()
}
#IBAction func selectRadioButton(_ sender: KGRadioButton) {
let chekIndex = self.checkIsRadioSelect.index(of: sender.tag)
_ = self.checkIsButtonEnable.index(of: sender.tag)
if sender.isSelected {
shippingTableView.isHidden = false
scrollView.isScrollEnabled = true
titleLabel.isHidden = false
} else{
if(chekIndex == nil){
self.checkIsRadioSelect.removeAll(keepingCapacity: false)
self.checkIsRadioSelect.append(sender.tag)
self.checkIsButtonEnable.removeAll(keepingCapacity: false)
self.checkIsButtonEnable.append(sender.tag)
self.tableDetails.reloadData()
}
}
}
func numberOfSections(in tableView: UITableView) -> Int{
var count = 0
if tableView.tag == 100{
return 1
}
else if tableView.tag == 110 {
return arrayss.count
}
return count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if tableView.tag == 100{
return "SHIPPING ADDRESS"
}
else {
return self.keys[section]
}
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
if tableView.tag == 100 {
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.gray
header.textLabel?.textAlignment = NSTextAlignment.center
header.textLabel?.font = UIFont(name: "Futura", size: 17)
}
else {
let header = view as! UITableViewHeaderFooterView
header.tintColor = UIColor.white
header.textLabel?.textColor = UIColor.darkGray
header.textLabel?.textAlignment = NSTextAlignment.left
header.textLabel?.font = UIFont(name: "Futura", size: 17)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if tableView.tag == 100{
return shippingArray.count
}
else {
var key = self.keys[section]
print(key)
var a :[Any] = arrayss[key] as! [Any]
return a.count
}
}
#IBAction func continueButtonAction(_ sender: Any) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "payment") as! paymentMethodViewController
self.present(nextViewController, animated:true, completion:nil)
}
#IBAction func deleteAction(_ sender: UIButton) {
shippingArray.remove(at:sender.tag)
self.tableDetails.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 100{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! addressTableViewCell
tableDetails.isHidden = false
myActivityIndicator.stopAnimating()
let arr = shippingArray[indexPath.row]
cell.deleteButton.tag = indexPath.row
cell.nameLabel.text = arr["name"] as? String
cell.addressLabel.text = arr["address"]as? String
let mobilenumber : Int = arr["number"] as! Int
cell.mobileNumberLabel.text = String(describing: mobilenumber)
cell.radioButton.tag = indexPath.row
cell.editButton.tag = indexPath.row
cell.deleteButton.tag = indexPath.row
cell.editButton.isHidden = true
cell.deleteButton.isHidden = true
let checkIndex = self.checkIsRadioSelect.index(of: indexPath.row)
if(checkIndex != nil){
shippingTableView.isHidden = false
scrollView.isScrollEnabled = true
titleLabel.isHidden = false
cell.radioButton.isSelected = true
cell.editButton.isHidden = false
cell.deleteButton.isHidden = false
}else{
cell.radioButton.isSelected = false
cell.editButton.isHidden = true
cell.deleteButton.isHidden = true
}
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "shippingCell", for: indexPath) as! shippingMethodTableViewCell
// let arr = detailsArray[indexPath.row]
// cell.methodNameLabel.text = arr.name
// cell.priceLabel.text = arr.price
var key = self.keys[indexPath.section]
print(key)
var a :[Any] = arrayss[key] as! [Any]
var dictionary = a[indexPath.row];
cell.methodNameLabel.text = dictionary ["name"] + dictionary ["price"]
return cell
}
}
any help would be of great appreciation

Sectional UITableView can rescue you from such situation. I have assumed arrayss as dictionary and jsonObj.
// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var key= self.keys[section]
print(key)
var a :[Any] = arrayss[key] as! [Any]
return a.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2 // if not fixed self.keys.count or self.arrayss.count
}
// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
var key= self.keys[indexPath.section]
print(key)
var a :[Any] = arrayss[key] as! [Any]
var dictionary = a[indexPath.row] as! [String:Any];
cell.textLabel.text = dictionary ["name"]+ dictionary ["price"] // you can set the text from the data model
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.keys[section]
}
---- EDIT----
In order to get all keys and values of dictionary from a dictionary separately.
var key = Array(arrayss.keys).sorted(by: >)
var values = Array(arrayss.values).sorted(by: >)
Hope it helps. Happy Coding!!

Related

Button in the table cell not working upon tapping

I am using below code for the UITableView, in every cell there are two buttons configured to perform certain actions as shown in the code. Earlier it was working fine, but now As I update this code to new version of Xcode it is not working, whenever I tap on the cell or the button in the cell it doesn't perform any action, neither it shows any error, but it just darkens the half of the cell with grey colour?
Xcode earlier was 10 and now 11, swift 5 version same in both cases
There is one fixed cell at the top and then there is list of cells as per the number of documents in the database
What could be the issue?
for information I am using Swift IOS and cloud firestore database
class HomeViewController: UITableViewController {
var posts = [Post]()
var db: Firestore!
var scores1 = [Scores]()
var postAuthorId:String = ""
var postAuthorname:String = ""
var CommentAuthorName:String = ""
var PostTitle:String = ""
var postAuthorGender:String = ""
var postAuthorEmail:String = ""
var postAuthorfullname:String = ""
var postAuthorSpinnerC:String = ""
var postContent:String = ""
var postCategory:String = ""
var postAuthorPicUrl:String = ""
var postTimeStamp:String = ""
var l11:Int = 0
var postKey:String = ""
private var documents: [DocumentSnapshot] = []
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
tableView.dataSource = self
tableView.delegate = self
retrieveAllPosts()
getuserscores()
var AViewController: UIViewController = UIViewController()
var MyTabBarItem: UITabBarItem = UITabBarItem(title: nil, image: UIImage(named: "pencil")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal), selectedImage: UIImage(named: "pencil"))
AViewController.tabBarItem = MyTabBarItem
// Do any additional setup after loading the view.
// navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(handleLogout))
}
func getuserscores(){
let userRef = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid)
userRef.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
let l1 = document.get("l1") as! Int
let l2 = document.get("l2") as! Int
let l3 = document.get("l3") as! Int
let l4 = document.get("l4") as! Int
let newScores = Scores(_l1: l1, _l2: l2, _l3: l3, _l4: l4)
self.scores1.append(newScores)
}
self.tableView.reloadData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func retrieveAllPosts(){
let postsRef = Firestore.firestore().collection("posts").order(by: "timestamp", descending: true).limit(to: 50)
postsRef.getDocuments { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
let username = data["post_author_username"] as? String ?? ""
let postTitle = data["postTitle"] as? String ?? ""
let postcategory = data["postcategory"] as? String ?? ""
let postContent = data["postContent"] as? String ?? ""
let postAuthorProfilePicUrl = data["post_user_profile_pic_url"] as? String ?? ""
let postAuthorSpinnerC = data["post_author_spinnerC"] as? String
let newSourse = Post(_documentId: document.documentID, _username: username, _postTitle: postTitle, _postcategory: postcategory, _postContent: postContent, _postuserprofileImagUrl: postAuthorProfilePicUrl, _postAuthorSpinncerC: postAuthorSpinnerC)
self.posts.append(newSourse)
}
self.tableView.reloadData()
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.estimatedRowHeight = 200
tableView.rowHeight = UITableView.automaticDimension
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return scores1.count + posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 && scores1.count == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SmileMiles") as! ScoresCellInHomeScreen
cell.set(scores: scores1[indexPath.row])
return cell
} else if posts.count > (indexPath.row - 1 ) {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.btnComment.tag = indexPath.row - 1
cell.btnComment.addTarget(self, action: #selector(toComments(_:)), for: .touchUpInside)
cell.favoritebutton.tag = indexPath.row - 1
cell.favoritebutton.addTarget(self, action: #selector(favupdate(_:)), for: .touchUpInside)
cell.set(post: posts[indexPath.row - 1 ])
return cell
} else {
return UITableViewCell()
}
}
#objc func favupdate(_ sender: AnyObject) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post._documentId // or what key value it is
let userMarkRef = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid).collection("marked_posts").document(postKey)
let postRef = Firestore.firestore().collection("posts").document(postKey)
postRef.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.postAuthorId = document.get("post_author_id") as! String
self.postAuthorname = document.get("post_author_username") as! String
self.PostTitle = document.get("postTitle") as! String
self.postContent = document.get("postContent") as! String
self.postAuthorEmail = document.get("post_author_email") as! String
self.postCategory = document.get("postcategory") as! String
self.postAuthorfullname = document.get("post_author_fullname") as! String
self.postAuthorGender = document.get("post_author_gender") as! String
self.postAuthorPicUrl = document.get("post_user_profile_pic_url") as! String
// let l11:Bool = document.get("l1") as! Bool
// self.postTimeStamp = document.get("post_timeStamp") as! String
self.postAuthorSpinnerC = document.get("post_author_spinnerC") as! String
}
let postObject = [
"post_author_gender": self.postAuthorGender,
// "post_author_dateOfBirth": self.dateOfBirth,
"post_author_spinnerC": self.postAuthorSpinnerC,
"post_author_fullname": self.postAuthorfullname,
"post_author_id": self.postAuthorId,
"post_author_username": self.postAuthorname,
"post_author_email": self.postAuthorEmail,
"postTitle": self.PostTitle,
"postcategory": self.postCategory,
"postContent": self.postContent,
// "post_timestamp": FieldValue.serverTimestamp(),
"post_user_profile_pic_url":self.postAuthorPicUrl,
"post_id": self.postKey
] as [String : Any]
userMarkRef.setData(postObject, merge: true) { (err) in
if let err = err {
print(err.localizedDescription)
}
print("Successfully set new user data")
}
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 150
}
else{
return UITableView.automaticDimension
}
}
#objc func toComments(_ sender: AnyObject) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post._documentId // or what key value it is
print(postKey + "hello")
performSegue(withIdentifier: "toCommentsList", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "toCommentsList"){
var vc = segue.destination as! CommentListViewController
vc.postId = postKey
}
}
}
Do this in tableview cellForRowAt function before return cell:
cell.selectionStyle = .none
return cell
this will fix the issue

Is it possible to add UITableView in UIScrollView?

The first two are working just fine but when the scroll horizontally to the third view that is table view the data is not getting populated. I am not what is going wrong in my code or it is not possible to achieve table view in scroll view?
The ScrollViewController code is mentioned below -
ScrollViewController
import UIKit
class ViewController: UIViewController {
var land = LandlordList()
var prop = PropertyList()
#IBOutlet weak var myScrollview: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let v1:ContactLandlord = ContactLandlord(nibName: "ContactLandlord", bundle: nil)
let v2:ContactLandlord2 = ContactLandlord2(nibName: "ContactLandlord2", bundle: nil)
let v3: PropertyTableVC = PropertyTableVC(nibName:"PropertyTableVC", bundle: nil)
self.addChildViewController(v1)
self.myScrollview.addSubview(v1.view)
v1.didMove(toParentViewController: self)
self.addChildViewController(v2)
self.myScrollview.addSubview(v2.view)
v2.didMove(toParentViewController: self)
self.addChildViewController(v3)
self.myScrollview.addSubview(v3.view)
v3.didMove(toParentViewController: self)
self.myScrollview.contentSize = CGSize(width: self.view.frame.width * 3, height: self.view.frame.size.height)
var v2frame: CGRect = v1.view.frame
v2frame.origin.x = self.view.frame.width
v2.view.frame = v2frame
var v3frame:CGRect = v2.view.frame
v3frame.origin.x = self.view.frame.width * 2
v3.view.frame = v3frame
v1.code.text = land.code
v1.titlelbl.text = land.title
v1.fname.text = land.firstName
v1.mname.text = land.middleName
v1.lname.text = land.lastName
v1.salutation.text = land.salutation
v1.add1.text = land.address1
v1.add2.text = land.address2
v1.add3.text = land.address3
v1.city.text = land.city
v1.area.text = land.area
v1.cluster.text = land.cluster
v2.email.text = land.email
v2.aemail.text = land.aemail
v2.cemail.text = land.certificationEmail
v2.memail.text = land.certificationEmail
v2.contact.text = land.contact
v2.hcontact.text = land.homeNumber
v2.wcontact.text = land.workNumber
v2.fcontact.text = land.faxNumber
let v4 = v3.propertyTabel.dequeueReusableCell(withIdentifier: "Cell") as? PropertyCell
v4?.propertyCodeLbl.text = prop.code
v4?.addressLbl.text = prop.address1
}
}
The PropertyTableVC is mentioned below -
PropertyTableVC
import UIKit
import Alamofire
class PropertyTableVC: UITableViewController {
#IBOutlet var propertyTabel: UITableView!
let URL_Landlord_Property_List = "http://127.0.0.1/source/api/LandlordPropertyList.php"
var count: Int = 0
var landlordPropertyArray: [PropertyList]? = []
override func viewDidLoad() {
super.viewDidLoad()
propertyTabel.dataSource = self
propertyTabel.delegate = self
fetchData()
let nibName = UINib(nibName: "PropertyCell", bundle:nil)
self.propertyTabel.register(nibName, forCellReuseIdentifier: "Cell")
}
func fetchData(){
let urlRequest = URLRequest(url: URL(string: URL_Landlord_Property_List)!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error != nil{
print(error!)
return
}
print(data!)
self.landlordPropertyArray = [PropertyList]()
self.count = (self.landlordPropertyArray?.count)!
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let datafromjson = json["landlords_property_list"] as? [[String: AnyObject]] {
print(datafromjson)
for data in datafromjson{
var property = PropertyList()
if let id = data["ID"] as? Int,let code = data["Code"] as? String, let address1 = data["Address"] as? String
{
property.id = id
property.code = code
property.address1 = address1
}
self.landlordPropertyArray?.append(property)
}
print(self.landlordPropertyArray)
DispatchQueue.main.async {
self.propertyTabel.reloadData()
}
}
}catch let error {
print(error)
}
}
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (landlordPropertyArray?.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PropertyCell
cell.propertyCodeLbl.text = self.landlordPropertyArray?[indexPath.item].code
cell.addressLbl.text = self.landlordPropertyArray?[indexPath.item].address1
return cell
}
}
The data in the tableView is loaded only when you conform to UITableViewDataSource UITableViewdelegate.
Use this , and have numberOfRows() and cellForRowAtIndexPath() in the class.
you will definitely get the populated tableView.

UITableViewCell are repeating and lost its data while scrolling

I have created a Form , in which I am using Textfields and TextField Dropdown. While I am scrolling the TableView textfields values got lost and textfield dropdown values set to default automatically.
Here is my code :
enum TextFieldTags:Int {
case ProspectName = 10, VisitDate, VisitType, Industry, Source, DissSummary, Requirements, FollowUpDate, AnticipatedDealValue, Probability, ExpectedClosingDate, Status, NextStep, Emp, Rev, AddressLine1, AddressLine2, Country, States, City, Zip, Mobile,Fax
}
var prospectName:String?, visitDate:String? , visitType:String?, industry:String?, source:String?, dissSummary:String?, requirements:String?, followUpDate:String?, anticipatedDealValue:String?, probability:String?, expectedClosingDate:String?, status:String?, nextStep:String?, emp:String?, rev:String?, addressLine1:String?, addressLine2:String?, country, statesVal:String?, cityVal:String?, zip:String?, mobile:String?,fax:String?
var currentLeadMaster:WizLeadMaster?
// MARK: - Section Data Structure
struct Section {
var name: String!
var options: [Any]!
var collapsed: Bool!
var optionItem:[Any]!
var icon:UIImage!
init(name: String, options: [Any], collapsed: Bool = false,optionItem:[Any],icon:UIImage) {
self.name = name
self.options = options
self.collapsed = collapsed
self.optionItem = optionItem
self.icon = icon
}
}
// MARK: - Properties
#IBOutlet weak var tblLeadDetail:UITableView?
var dataSource:NSArray = NSArray(objects: "Lead Summary","Address","Products","Contacts","Attachment","Follow Up","Remarks")
var sections = [Section]()
lazy var visitArr:NSArray = {
let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMVisittype)
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizLookUp
let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
lazy var leadStatus:NSArray = {
let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMLeadStatus)
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizLookUp
let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
lazy var leadSource:NSArray = {
let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMLeadsource)
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizLookUp
let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
lazy var industries:NSArray = {
let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMCustomerType)
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizLookUp
let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
lazy var countries:NSArray = {
let visitTypes = Handler.countriesList()
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizCountryList
let dict = ["system":(visitModel.lable! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
lazy var states:NSArray = {
let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMTerritory)
var optionsArray = NSMutableArray(capacity: 0)
for visitType in visitTypes {
let visitModel = visitType as! WizLookUp
let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]
optionsArray.add(dict as NSDictionary)
}
return optionsArray as NSArray
}()
func setStatesForCountry(_ country:String) -> Void{
}
func filterValue(_ arr:NSArray,key:String) -> Any {
let predicate = NSPredicate(format: "self == %#", key)
let filteredArr = arr.filtered(using: predicate)
if (filteredArr.count == 0) {
return ""
}
return filteredArr[0]
}
// MARK: - ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let barButtonItem = UIBarButtonItem(image:UIImage(named:"save1") , style: UIBarButtonItemStyle.done, target: self, action: #selector(saveLeadInfo))
navigationItem.rightBarButtonItem = barButtonItem
sections = [
Section(name: "Lead Summary", options: [["title":"Prospect Name","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.customer_name as Any,"tag":TextFieldTags.ProspectName.rawValue],
["title":"Visit Date","type":"date","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.visited_date as Any,"tag":TextFieldTags.VisitDate.rawValue],
["title":"Visit Type","type":"dropdown","options":visitArr.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.VisitType.rawValue],
["title":"Industry","type":"dropdown","options":industries.value(forKeyPath: "system"),"value":filterValue(industries.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.type)!),"tag":TextFieldTags.Industry.rawValue],
["title":"Source","type":"dropdown","options":leadSource.value(forKeyPath: "system"),"value":filterValue(leadSource.value(forKeyPath: "value") as! NSArray , key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.source)!),"tag":TextFieldTags.Source.rawValue],
["title":"Discussion Summary","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.summary_disc as Any,"tag":TextFieldTags.DissSummary.rawValue],
["title":"Requirements","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.requirements as Any ,"tag":TextFieldTags.Requirements.rawValue],
["title":"Follow-Up Date","type":"date","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.followup_date as Any,"tag":TextFieldTags.FollowUpDate.rawValue],
["title":"Anticipated Deal Value","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.anticipated_deal_value as Any,"tag":TextFieldTags.AnticipatedDealValue.rawValue],
["title":"Probabilty","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.probability as Any,"tag":TextFieldTags.Probability.rawValue],
["title":"Expected Closing Date","type":"date","value":currentLeadMaster?.expected_closing_date as Any,"tag":TextFieldTags.ExpectedClosingDate.rawValue],
["title":"Status","type":"dropdown","options":leadStatus.value(forKeyPath: "system"),"value":filterValue(leadStatus.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.status)!),"tag":TextFieldTags.Status.rawValue],
["title":"Next Step","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.next_activity_planned as Any,"tag":TextFieldTags.NextStep.rawValue],
["title":"Emp","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.no_of_emp as Any,"tag":TextFieldTags.Emp.rawValue],
["title":"Rev","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.annual_revenue as Any,"tag":TextFieldTags.Rev.rawValue]], collapsed: true, optionItem: [],icon:UIColor.clear.getImage(size: CGSize(width: 30, height: 30))),
Section(name: "Address", options: [["title":"Address Line 1","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline1 as Any ,"tag":TextFieldTags.AddressLine1.rawValue],
["title":"Address Line 2","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.AddressLine2.rawValue],
["title":"Select Country","type":"dropdown","options":countries.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.Country.rawValue],
["title":"Select States","type":"dropdown","options":visitArr.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.States.rawValue],
["title":"Select City","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.City.rawValue],
["title":"Zip Code","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Zip.rawValue],
["title":"Mobile","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Mobile.rawValue],
["title":"Fax","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Fax.rawValue]
], collapsed: true, optionItem: [],icon:UIColor.clear.getImage(size: CGSize(width: 30, height: 30))),
Section(name: "Product", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "add")!),
Section(name: "Contacts", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "add")!),
Section(name: "Attachment", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "attach")!),
]
let headerNib = UINib(nibName: "WizHeaderView", bundle: nil)
tblLeadDetail?.register(headerNib, forHeaderFooterViewReuseIdentifier: "headerLeads")
let textInputCell = UINib(nibName: "TextInputCell", bundle: nil)
tblLeadDetail?.register(textInputCell, forCellReuseIdentifier: "textinputcell")
let dropDownInputCell = UINib(nibName: "DropDownInputCell", bundle: nil)
tblLeadDetail?.register(dropDownInputCell, forCellReuseIdentifier: "dropDownInputCell")
let dropDownDateCell = UINib(nibName: "DropDownDateCell", bundle: nil)
tblLeadDetail?.register(dropDownDateCell, forCellReuseIdentifier: "dropDownDateCell")
tblLeadDetail?.reloadData()
}
func saveLeadInfo() -> Void {
}
// MARK: - TableView Delegates & Datasource
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let optionsArray = sections[section].options
return optionsArray!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let optionsArray = sections[indexPath.section].options
let dict = optionsArray?[indexPath.row] as! Dictionary<String,Any>
if (dict["type"] as! String == "dropdown") {
let cell = tableView.dequeueReusableCell(withIdentifier: "dropDownInputCell") as! DropDownInputCell
cell.txtInput.isOptionalDropDown = false
cell.txtInput.itemList = dict["options"] as! [String]
cell.lblText.text = dict["title"] as? String
cell.txtInput.selectedItem = dict["value"] as? String
cell.txtInput.tag = (dict["tag"] as? NSInteger)!
cell.backgroundColor = UIColor.clear
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.delegate = self
return cell
}
else if (dict["type"] as! String == "input") {
let cell = tableView.dequeueReusableCell(withIdentifier: "textinputcell") as! TextInputCell
cell.lblText.text = dict["title"] as? String
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.backgroundColor = UIColor.clear
cell.txtInput.text = dict["value"] as? String
cell.txtInput.tag = (dict["tag"] as? NSInteger)!
cell.delegate = self
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "dropDownDateCell") as! DropDownDateCell
cell.lblText.text = dict["title"] as? String
cell.txtInput.dropDownMode = IQDropDownMode.datePicker
if dict["value"] as? String == "" {
cell.txtInput.setDate(Date(), animated: true)
}
else{
cell.txtInput.selectedItem = dict["value"] as? String
}
cell.txtInput.tag = (dict["tag"] as? NSInteger)!
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.backgroundColor = UIColor.clear
cell.delegate = self
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// if indexPath.row == 0 {
// performSegue(withIdentifier: "leadsummary", sender:nil)
// }
// else{
// performSegue(withIdentifier: "leadaddress", sender:nil)
// }
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerLeads") as? WizHeaderView ?? WizHeaderView(reuseIdentifier: "headerLeads")
header.delegate = self
header.lblLeadSummary.text = sections[section].name
header.btnArrowButton.setImage(sections[section].icon, for: UIControlState.normal)
header.setCollapsed(sections[section].collapsed)
header.section = section
return header
}
func toggleSection(_ header: WizHeaderView, section: Int) {
let collapsed = !sections[section].collapsed
// Toggle collapse
sections[section].collapsed = collapsed
header.setCollapsed(collapsed)
// Adjust the height of the rows inside the section
tblLeadDetail?.beginUpdates()
for i in 0 ..< sections[section].options.count {
tblLeadDetail?.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}
tblLeadDetail?.endUpdates()
}
#IBAction func placeOrder(_ sender: Any) {
let placeOrder = MainStoryBoard.instantiateViewController(withIdentifier: "PlaceOrder")
navigationController?.pushViewController(placeOrder, animated: true)
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 35.0
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 10.0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return sections[(indexPath as NSIndexPath).section].collapsed! ? 0 : 70.0
}
func cellTextField(_with TextField: IQDropDownTextField, didSelectItem item: String?) {
switch TextField.tag {
case TextFieldTags.VisitType.rawValue:
visitType = item
break
case TextFieldTags.Industry.rawValue:
industry = item
break
case TextFieldTags.Source.rawValue:
source = item
break
case TextFieldTags.Status.rawValue:
status = item
break
case TextFieldTags.Country.rawValue:
country = item
break
case TextFieldTags.States.rawValue:
statesVal = item
break
default: break
}
}
func cellTextFieldDidEndEditing(_with textField: UITextField) {
switch textField.tag {
case TextFieldTags.ProspectName.rawValue:
prospectName = textField.text
break
case TextFieldTags.DissSummary.rawValue:
dissSummary = textField.text
break
case TextFieldTags.Requirements.rawValue:
requirements = textField.text
break
case TextFieldTags.AnticipatedDealValue.rawValue:
anticipatedDealValue = textField.text
break
case TextFieldTags.Probability.rawValue:
probability = textField.text
break
case TextFieldTags.NextStep.rawValue:
nextStep = textField.text
break
case TextFieldTags.Emp.rawValue:
emp = textField.text
break
case TextFieldTags.Rev.rawValue:
rev = textField.text
break
case TextFieldTags.AddressLine1.rawValue:
addressLine1 = textField.text
break
case TextFieldTags.AddressLine2.rawValue:
addressLine2 = textField.text
break
case TextFieldTags.City.rawValue:
cityVal = textField.text
break
case TextFieldTags.Mobile.rawValue:
mobile = textField.text
break
case TextFieldTags.Fax.rawValue:
fax = textField.text
break
case TextFieldTags.Zip.rawValue:
zip = textField.text
break
default: break
}
}
func stringFromDate(_ date:Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter.string(from: date)
}
func cellTextFieldDate(_with textField: IQDropDownTextField, didSelect date: Date?) {
switch textField.tag {
case TextFieldTags.VisitDate.rawValue:
visitDate = stringFromDate(date!)
break
case TextFieldTags.FollowUpDate.rawValue:
followUpDate = stringFromDate(date!)
break
case TextFieldTags.ExpectedClosingDate.rawValue:
expectedClosingDate = stringFromDate(date!)
break
default: break
}
}
}
extension UIColor {
func getImage(size: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image(actions: { rendererContext in
self.setFill()
rendererContext.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
})
}}
While using UITableView with reusable cell identifier, you have to store input of your UITextField or any other input fields when editing is finished into your data source which you are using to fill all cells. Because reusable cell manage memory itself to draw all your controls, so there are no guaranty about your data remains as it is when you scroll your tableview.
In this if - else expression
if dict["value"] as? String == "" {
cell.txtInput.setDate(Date(), animated: true)
} else{
cell.txtInput.selectedItem = dict["value"] as? String
}
you are setting two different UI elements depending on the dictionary value.
As cells are reused those UI states will remain until they are changed the next time.
You have to make sure that every UI element is set to a defined state to avoid unexpected behavior, so you need to set the other UI element, too. For example ([default value] is just a placeholder).
if dict["value"] as? String == "" {
cell.txtInput.setDate(Date(), animated: true)
cell.txtInput.selectedItem = [default value]
} else{
cell.txtInput.setDate([default value], animated: [default value])
cell.txtInput.selectedItem = dict["value"] as? String
}
If there is no unique default value you have to add properties to the data source to keep the current states of the date and the selected item.
Regarding the text field you have to update the data source after changing the text because in cellForRow the text field is always updated from the data source.
And - as always - don't use NS(Mutable)Array and NS(Mutable)Dictionary in Swift. You throw away the important type information and the mutable collection types are not related to the Swift native types. Finally you can delete all break lines in the switch expressions (except after default). They are redundant in Swift.

In table view data was not loading and after json parsing the app was craashing

when i keep break points at the point mentioned in image then the data was loading without crashing the application and when i didn't kept the break points and make the application to run then it was crashing can any one help me how to clear the error
my code is shown below
let url = "http://www.json-generator.com/api/json/get/bUKEESvnvS?indent=2"
var orderdetailsArray : [[String:AnyObject]] = []
var itemsArray : [[String:AnyObject]] = []
var orderid = [Any]()
var orderdate = [Any]()
var subTotal = [Int]()
var shippingPrice = [Int]()
var tax = [Int]()
var grandTotal = [Int]()
var shippingAddress = [AnyObject]()
var shippingMethod = [AnyObject]()
var billingAddress = [AnyObject]()
var paymentMethod = [AnyObject]()
override func viewDidLoad() {
super.viewDidLoad()
self.downloadJsonWithURL()
tableDetails.delegate = self
tableDetails.dataSource = self
tableDetails.estimatedRowHeight = 600
// Do any additional setup after loading the view.
}
func downloadJsonWithURL() {
let url = NSURL(string: self.url)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
self.orderdetailsArray = (jsonObj!.value(forKey: "Orders detail") as? [[String: AnyObject]])!
if let firstDictInfo = self.orderdetailsArray.first as? [String:Any] {
self.itemsArray = firstDictInfo["Items detail"] as! [[String : AnyObject]]
}
OperationQueue.main.addOperation({
self.tableDetails.reloadData()
})
}
}).resume()
}
func numberOfSections(in tableView: UITableView) -> Int{
return 3
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (section == 0){
return ""
}
else if (section == 1){
return ""
}
else{
return "Ordered Items"
}
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.darkGray
header.textLabel?.textAlignment = NSTextAlignment.center
header.textLabel?.font = UIFont(name: "Futura", size: 17)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0){
return 1
}else if (section == 1){
return 1
}
else{
return itemsArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.section == 0)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "ordercell", for: indexPath) as! OrdersTableViewCell
cell.orderDateLabel.text = orderdetailsArray[0]["OrderDate"] as? String
cell.orderIdLabel.text = orderdetailsArray[0]["OrderId"]! as? String
let totalPrice : Int = orderdetailsArray[0]["Shipping"]! as! Int
let price = Float(totalPrice)
cell.shippingLabel.text = "$" + "\(price)"
let subTotalPrice : Int = orderdetailsArray[0]["SubTotal"]! as! Int
let subtotalprice = Float(subTotalPrice)
cell.subTotalLabel.text = "$" + "\(subtotalprice)"
let taxPrice : Int = orderdetailsArray[0]["Tax"]! as! Int
let taxPriceFloat = Float(taxPrice)
cell.taxLabel.text = "$" + "\(taxPriceFloat)"
let grandTotal : Int = self.orderdetailsArray[0]["GrandTotal"]! as! Int
let grandPriceFloat = Float(grandTotal)
cell.grandTotalLabel.text = "$" + "\(grandPriceFloat)"
return cell
}
else if (indexPath.section == 1){
let cell = tableView.dequeueReusableCell(withIdentifier: "shippingcell", for: indexPath) as! ShippingTableViewCell
cell.shippingMethodLabel.text = orderdetailsArray[0]["ShippingMethod"] as? String
cell.shippingAddressLabel.text = orderdetailsArray[0]["ShippingAddress"]! as? String
cell.billingAddressLabel.text = orderdetailsArray[0]["BillingAddress"]! as? String
cell.paymentMethodLabel.text = orderdetailsArray[0]["PayMentMethod"]! as? String
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "orderdetailscell", for: indexPath) as! OrderDetailsTableViewCell
let array = itemsArray[indexPath.row]
let price : Int = array["ItemPrice"] as! Int
let grandPriceFloat = Float(price)
cell.priceLabel.text = "$" + "\(grandPriceFloat)"
let quant : Int = array["ItemQty"] as! Int
cell.quantityLabel.text = "\(quant)"
cell.productNameLabel.text = array["ItemName"] as? String
let subTotal : Int = array["ItemSubTotal"] as! Int
let subPriceFloat = Float(subTotal)
cell.subTotalLabel.text = "$" + "\(subPriceFloat)"
let grandTotal : Int = array["ItemSku"] as! Int
cell.skuLabel.text = "\(grandTotal)"
return cell
}
}
You need to confirm if orderDetailsArray actually contains some value before you are accessing it. Also, you are just returning 1 for numberOfRowsInSection without even checking if orderDetailsArray has some content. This should possibly resolve your crash:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0 || section == 1) {
if orderDetailsArray.count > 0 {
return 1
} else {
return 0
}
}
else {
return itemsArray.count
}
}
I am not sure if this is the kind of behavior you are expecting because it will result in section Headers with no rows but, you can modify that!
Need to register UINib in UITableView for use multiple custom cell in tableView.
How to register UINib in UITableView?
Just write below three line in ViewDidLoad()
tableView.register(UINib(nibName: "ShippingTableViewCell", bundle: nil), forCellReuseIdentifier: "shippingcell")
tableView.register(UINib(nibName: "OrderDetailsTableViewCell", bundle: nil), forCellReuseIdentifier: "orderdetailscell")
tableView.register(UINib(nibName: "OrdersTableViewCell", bundle: nil), forCellReuseIdentifier: "ordercell")

Get cells from last section uitableview

I have dynamically tableview with many section whitch is adding in run time by tap on button.
This button must send data from cells in last section (many type of custom cells).
How can i get cells or indexpath's of cells in last section?
I was trying to add these cells to array in cellForRowAtIndexPath, but i use dequeueReusableCellWithIdentifier to create this cells, so this is problematic.
Edit:
My code:
class ProcessViewController: UITableViewController, SWRevealViewControllerDelegate{
//this will be cell
struct field {
var name, type, id, hint, output, specialType:String
var selectOptions:NSMutableArray
var settings:NSArray
}
struct group {
var name:String
var fields:[field]
}
// this will be sections
struct block {
var groups:[group]
var id, name:String
}
var blocks:[block] = []
//fields in last (active) block
//var fields:[field] = []
//array of cells with some input
var cellsInTable:NSMutableArray = []
var cellWithCustomHeight:[NSIndexPath] = []
#IBOutlet var sendFormButton: UIButton!
var jsonData:NSDictionary?
#IBOutlet var menuButton: UIBarButtonItem!
var allfields:[field] = []
var numberOfOldCells = 0
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.barTintColor = UIColor(red: 62/255.0, green: 80/255.0, blue: 178/255.0, alpha: 1);
//print("json w srodku \(self.jsonData)")
if self.revealViewController() != nil {
self.revealViewController().delegate = self
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
//print(self.jsonData)
let data = self.jsonData?.valueForKey("data") as! NSMutableDictionary
//set title of the screen
self.title = data.valueForKey("name") as? String
//hide button if process is completed
if(data.valueForKey("progress") as! Int == 1){
sendFormButton.hidden = true
//print("asdasd")
}
parseData(data)
//print("Bloki: \(self.blocks)")
}
func parseData(data:NSMutableDictionary){
self.cellsInTable = []
//blocks is the sections in tableView, fields is a cells and groups (for now)
let blocks = data.valueForKey("blocks") as! NSMutableArray
self.blocks = []
self.allfields = []
blocks.enumerateObjectsUsingBlock {obj, i, stop in
//print( obj.valueForKey("input"))
var inputs:NSMutableArray = []
//get inputs from current block, if input is only one it is dictionary in swift
if let kinputs = obj.valueForKey("input") as? NSArray{
inputs = NSMutableArray(array:kinputs)
}else{
inputs.addObject(obj.valueForKey("input")!)
}
inputs.removeLastObject()
var outputs:NSArray = []
if let koutputs = obj.valueForKey("output") as? NSArray{
outputs = koutputs
}
//print("wrona \(outputs) kracze razy: \(outputs.count)")
var tmpGroups:[group] = []
//inupt is a group
inputs.enumerateObjectsUsingBlock({input, j, stop in
//print("input w petli: \(input)")
if(input.valueForKey("fields") != nil){
let forms = NSMutableArray(array:input.valueForKey("fields") as! NSArray)
var tmpFields:[field] = []
let groupField:field = field(name:
input.valueForKey("name") as! String,
type: "group",
id: "0",
hint: input.valueForKey("name") as! String,
output: "",
specialType: "group",
selectOptions: [],
settings:[]
)
tmpFields.append(groupField)
forms.enumerateObjectsUsingBlock({fieldObj, k, stop in
let fromId = fieldObj.valueForKey("id") as! String
var output:String = ""
let tmpOutputs = outputs.valueForKey(fromId) as! NSArray
print(tmpOutputs)
print(output)
if tmpOutputs.count != 0{
if let _ = tmpOutputs[0] as? NSString{
output = tmpOutputs[0] as! String
}
} else {
//print(outputs.valueForKey(String(k)))
}
let selectOptions = NSMutableArray(array: fieldObj.valueForKey("selectOptions") as! NSArray)
//print("asdasdad\(fieldObj)")
let tmpField:field = field(
name: fieldObj.valueForKey("name") as! String,
type: fieldObj.valueForKey("type") as! String,
id: fromId,
hint: fieldObj.valueForKey("hint") as! String,
output:output,
specialType: fieldObj.valueForKey("specialType") as! String,
selectOptions: selectOptions,
settings:fieldObj.valueForKey("settings") as! NSArray
)
tmpFields.append(tmpField)
})
let tmpGroup:group = group(name: input.valueForKey("name") as! String, fields: tmpFields)
tmpGroups.append(tmpGroup)
}
})
let tmpBlock:block = block(groups: tmpGroups,
id: obj.valueForKey("id") as! String,
name: obj.valueForKey("name") as! String
)
self.blocks.append(tmpBlock)
}
}
func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) {
UIApplication.sharedApplication().sendAction("resignFirstResponder", to:nil, from:nil, forEvent:nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.blocks[section].name as String
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return blocks.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var formsInGroup:Int = 0;
for group in self.blocks[section].groups{
formsInGroup += group.fields.count
}
return formsInGroup
//return blocks[section].fields.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(self.cellWithCustomHeight.contains(indexPath)){
return CGFloat(132)
} else {
return CGFloat(47)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//geting fields in current group
self.allfields = []
for group in self.blocks[indexPath.section].groups {
self.allfields.appendContentsOf(group.fields)
}
print("bloki \(self.blocks.count), sekcje: \(indexPath.section)")
//print(self.allfields.count)
let cellType = self.allfields[indexPath.row].type as String
//print("row: \(indexPath.row), sections: \(indexPath.section)")
switch cellType {
case "group":
let cell = tableView.dequeueReusableCellWithIdentifier("groupCell", forIndexPath: indexPath) as! groupCell
cell.groupName.text = self.allfields[indexPath.row].name
return cell
case "text":
if(self.allfields[indexPath.row].specialType == "date"){
let cell = tableView.dequeueReusableCellWithIdentifier("datePickerCell", forIndexPath: indexPath) as! datePickerCell
cell.hint.text = self.allfields[indexPath.row].name as String
let output = self.allfields[indexPath.row].output as String
cell.selectionStyle = UITableViewCellSelectionStyle.None
self.cellWithCustomHeight.append(indexPath)
if(output != ""){
print(self.allfields[indexPath.row].name)
//print( " output: \(output)")
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-mm-yyyy"
let date = dateFormatter.dateFromString(self.allfields[indexPath.row].output)
cell.date.setDate(date!, animated: false)
cell.date.userInteractionEnabled = false
}
if !self.cellsInTable.containsObject(cell){
self.cellsInTable.addObject(cell)
}
setCellsToSend(indexPath.section)
return cell
}else{
let cell = tableView.dequeueReusableCellWithIdentifier("textCell", forIndexPath: indexPath) as! textCell
cell.hint.text = self.allfields[indexPath.row].name as String
let output = self.allfields[indexPath.row].output as String
cell.settings = self.allfields[indexPath.row].settings
if self.allfields[indexPath.row].specialType == "number" {
cell.input.keyboardType = UIKeyboardType.NumberPad
}
cell.input.text = ""
cell.selectionStyle = UITableViewCellSelectionStyle.None
if(output != ""){
//print(fields[indexPath.row].name)
//print(output)
cell.input.text = self.allfields[indexPath.row].output
cell.input.userInteractionEnabled = false
}
if !self.cellsInTable.containsObject(cell){
self.cellsInTable.addObject(cell)
} else {
print("kuuuuuurwa \(self.allfields[indexPath.row].name)")
}
setCellsToSend(indexPath.section)
return cell
}
case "checkbox":
let cell = tableView.dequeueReusableCellWithIdentifier("checkBoxCell", forIndexPath: indexPath) as! checkBoxCell
cell.selections = self.allfields[indexPath.row].selectOptions
cell.hint.text = self.allfields[indexPath.row].name as String
cell.settings = self.allfields[indexPath.row].settings
cell.indexPath = indexPath
cell.selectionStyle = UITableViewCellSelectionStyle.None
if !self.cellsInTable.containsObject(cell){
self.cellsInTable.addObject(cell)
} else {
print("kuuuuuurwa \(self.allfields[indexPath.row].name)")
}
setCellsToSend(indexPath.section)
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier("unknownCell", forIndexPath: indexPath)
cell.textLabel?.text = "niezaimplementowany typ pola: \(cellType)"
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
}
func setCellsToSend(sectionInTable:Int){
if(sectionInTable == self.blocks.count-2){
print("sekcja \(sectionInTable)")
self.numberOfOldCells = self.cellsInTable.count
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "showCheckBox"){
let checkBoxController = segue.destinationViewController as! CheckBoxController
let cell = sender as! checkBoxCell
//print(cell.settings)
checkBoxController.selections = cell.selections
checkBoxController.multiple = checkboxMultiValue(cell.settings)
checkBoxController.indexPath = cell.indexPath
checkBoxController.selected = cell.output
}
}
func checkboxMultiValue(settings:NSArray)->Bool{
var boolToReturn:Bool = false
settings.enumerateObjectsUsingBlock({obj, i, end in
if(obj.valueForKey("name") as! String == "multi_values"){
if( obj.valueForKey("checked") as! String == "multi_values"){
boolToReturn = true;
}
}
//print(i)
})
return boolToReturn
}
#IBAction func saveSelectedSelections(segue: UIStoryboardSegue) {
let checkBoxController = segue.sourceViewController as! CheckBoxController
let selectedRowsPath = checkBoxController.tableView.indexPathsForSelectedRows
var output:[String] = []
if(selectedRowsPath?.count > 0){
for rowPath in selectedRowsPath!{
let cell = checkBoxController.tableView.cellForRowAtIndexPath(rowPath) as! selectionCell
output.append(cell.nameLabel.text! as String)
}
}
let cell = self.tableView.cellForRowAtIndexPath(checkBoxController.indexPath!) as! checkBoxCell
cell.output = output
}
#IBAction func sendForm(sender: AnyObject) {
print("\(self.numberOfOldCells) i \(self.cellsInTable.count)")
var postData:Dictionary<Int, AnyObject> = [:]
var post = ""
var iterator:Int = 0
for var i = self.numberOfOldCells; i < self.cellsInTable.count; ++i{
if let cellText = self.cellsInTable[i] as? textCell{
//print("cellText \(cellText.input.text as String!)")
postData[iterator] = cellText.input.text as AnyObject!
post += "\(iterator):{'\(cellText.input.text! as String)'}&"
iterator++
} else if let cellCheckBox = self.cellsInTable[i] as? checkBoxCell{
//print(cellCheckBox.output)
let checkBoxOutput = cellCheckBox.output
var data:String = ""
for var i = 0; i < checkBoxOutput.count; ++i {
if ( i == 0) {
data += checkBoxOutput[i]
}else{
data += ";\(checkBoxOutput[i])"
}
}
post += "\(iterator):{'\(data)'}&"
postData[iterator] = data as AnyObject!
//postData.append(data as String!)
iterator++
}else if let cellDate = self.cellsInTable[i] as? datePickerCell{
//print(cellDate.date.date)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-mm-yyyy"
let date = dateFormatter.stringFromDate(cellDate.date.date)
postData[iterator] = date as AnyObject!
post += "\(iterator):{'\(date)'}&"
//postData.append(date as String!)
iterator++
}
}
//print("Post data:\(postData)")
//getNewBlock(NSKeyedArchiver.archivedDataWithRootObject(postData))
print(post)
getNewBlock(post.dataUsingEncoding(NSASCIIStringEncoding)!)
}
func getNewBlock(postData:NSData){
//print("Post data jako nsdata:\(postData)")
//var blockId = "a"
let blockId = blocks.last!.id
let url:NSURL = NSURL(string: "http://app.proces.io/Cloud/?Systems/Proces/Process/Block/makeAction/id-\(blockId)")!
print(url)
let postLength:NSString = String( postData.length )
let request:NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = postData
request.setValue(postLength as String, forHTTPHeaderField: "Content-Length")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
urlData, response, error in
var requestData: NSDictionary?
do{
requestData = try NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers ) as? NSDictionary
//print(requestData)
if ( requestData != nil ) {
let success:NSInteger = requestData!.valueForKey("success") as! NSInteger
if(success == 1)
{
//print(self.blocks.count)
let data = requestData!.valueForKey("process") as! NSMutableDictionary
//print(self.allfields)
//self.numberOfOldCells = self.cellsInTable.count
//print(self.blocks)
self.allfields = []
self.parseData(data)
//print(self.blocks.count)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
} else {
print("cos poszlo nie tak \(requestData?.valueForKey("validation_errors")), values: \(requestData?.valueForKey("values"))")
}
}
} catch let error as NSError{
print("cos poszlo nie tak: \(error)")
}
}
task.resume()
}
Edit 2: minimal version with some explains:
class ProcessViewController: UITableViewController, SWRevealViewControllerDelegate{
//this will be cell
struct field {
var name, type, id, hint, output, specialType:String
var selectOptions:NSMutableArray
var settings:NSArray
}
struct group {
var name:String
var fields:[field]
}
// this will be sections
struct block {
var groups:[group]
var id, name:String
}
var blocks:[block] = []
var jsonData:NSDictionary?
#IBOutlet var menuButton: UIBarButtonItem!
var allfields:[field] = []
var numberOfOldCells = 0
override func viewDidLoad() {
super.viewDidLoad()
parseData(data)
}
func parseData(data:NSMutableDictionary){
//in this function i have a parsing data from json, whitch create me array of blocks (global variable "blocks")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.blocks[section].name as String
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return blocks.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var formsInGroup:Int = 0;
for group in self.blocks[section].groups{
formsInGroup += group.fields.count
}
return formsInGroup
//return blocks[section].fields.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(self.cellWithCustomHeight.contains(indexPath)){
return CGFloat(132)
} else {
return CGFloat(47)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//geting fields in current group
self.allfields = []
for group in self.blocks[indexPath.section].groups {
self.allfields.appendContentsOf(group.fields)
}
let cellType = self.allfields[indexPath.row].type as String
switch cellType {
case "group":
let cell = tableView.dequeueReusableCellWithIdentifier("groupCell", forIndexPath: indexPath) as! groupCell
cell.groupName.text = self.allfields[indexPath.row].name
return cell
case "text":
if(self.allfields[indexPath.row].specialType == "date"){
let cell = tableView.dequeueReusableCellWithIdentifier("datePickerCell", forIndexPath: indexPath) as! datePickerCell
cell.hint.text = self.allfields[indexPath.row].name as String
let output = self.allfields[indexPath.row].output as String
cell.selectionStyle = UITableViewCellSelectionStyle.None
self.cellWithCustomHeight.append(indexPath)
if(output != ""){
print(self.allfields[indexPath.row].name)
//print( " output: \(output)")
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-mm-yyyy"
let date = dateFormatter.dateFromString(self.allfields[indexPath.row].output)
cell.date.setDate(date!, animated: false)
cell.date.userInteractionEnabled = false
}
return cell
}else{
let cell = tableView.dequeueReusableCellWithIdentifier("textCell", forIndexPath: indexPath) as! textCell
cell.hint.text = self.allfields[indexPath.row].name as String
let output = self.allfields[indexPath.row].output as String
cell.settings = self.allfields[indexPath.row].settings
if self.allfields[indexPath.row].specialType == "number" {
cell.input.keyboardType = UIKeyboardType.NumberPad
}
cell.input.text = ""
cell.selectionStyle = UITableViewCellSelectionStyle.None
if(output != ""){
cell.input.text = self.allfields[indexPath.row].output
cell.input.userInteractionEnabled = false
}
return cell
}
case "checkbox":
let cell = tableView.dequeueReusableCellWithIdentifier("checkBoxCell", forIndexPath: indexPath) as! checkBoxCell
cell.selections = self.allfields[indexPath.row].selectOptions
cell.hint.text = self.allfields[indexPath.row].name as String
cell.settings = self.allfields[indexPath.row].settings
cell.indexPath = indexPath
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier("unknownCell", forIndexPath: indexPath)
cell.textLabel?.text = "niezaimplementowany typ pola: \(cellType)"
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
}
#IBAction func sendForm(sender: AnyObject) {
// in this function i must send data from cells in last section and add new section on the basis of request
}

Resources