How can I update my datasource and animate the changes with RxSwift in my tableview? - uitableview

Datasource is updating, but the changes are not being displayed in the Tableview.
I am experimenting with Friends, Users, & Users Request tableview with 3 sections. When a user has a request from a user, he or she appears under the request section. However, when the user clicks "accept" the console is reading it's hitting the firebase server, but the changes that that request was actually made is not registering and the request remains in the section until you reload the view. I have tried forcing a tableview to reload, but to no avail.
struct SectionOfuserRxx {
var header: String
var items: [Item]
}
extension SectionOfuserRxx: IdentifiableType {
}
extension SectionOfuserRxx: AnimatableSectionModelType {
// typealias Item = user
typealias Identity = String
////
typealias Item = user
init(original: SectionOfuserRxx, items: [Item]) {
self = original
self.items = items
}
var identity: String {
return header
}
}
// Above viewDidLoad
let disposeBag = DisposeBag()
//
//Inside viewDidLoad
let dataSource = RxTableViewSectionedAnimatedDataSource<SectionOfuserRxx>(
configureCell: { dataSource, tableView, indexPath, item in
switch (indexPath.section) {
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as? userCell
let userProfileImageURLFirebaseReturn = item.userImageURL
let userNameTagFirebaseReturn = item.nametag
let userNameFirebaseReturn = item.username
let imageURL = userProfileImageURLFirebaseReturn
let resource = ImageResource(downloadURL: URL(string: imageURL!)!, cacheKey: userProfileImageURLFirebaseReturn)
cell?.userProfileImage.kf.setImage(with: resource)
cell?.usernameLbl.text = userNameFirebaseReturn
cell?.userNameTagLbl.text = "| " + userNameTagFirebaseReturn!
cell!.setFunction {
cell!.button.isEnabled = true
let id = item.userUID
FriendSystem.system.sendRequestToUser(id!)
}
return cell!
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "friendsCell", for: indexPath) as? friendsCell
cell!.buttons.isEnabled = true
cell!.buttons.setTitle("Remove", for: UIControl.State())
// print("Friend Count: \(item.count)");
print(" INDEXING ROW FOR FRIENDS: \(indexPath.row)")
let userProfileImageURLFirebaseReturn = item.userImageURL ?? ""
let userNameTagFirebaseReturn = item.nametag ?? ""
let userNameFirebaseReturn = item.username ?? ""
let imageURL = userProfileImageURLFirebaseReturn
// self.urlContentArray.append(imageURL)
if imageURL != "" {
let resource = ImageResource(downloadURL: URL(string: imageURL)!, cacheKey: userProfileImageURLFirebaseReturn)
cell?.userProfileImage.kf.setImage(with: resource)
} else {
cell?.userProfileImage.image = UIImage(named: "heartfilled")
}
cell?.usernameLbl.text = userNameFirebaseReturn
cell?.userNameTagLbl.text = userNameTagFirebaseReturn;
cell!.setFunction {
cell!.buttons.isEnabled = true
let id = item.userUID
// FriendSystem.system.friendList.remove(at: indexPath.row)
FriendSystem.system.removeFriend(id!)
}
return cell!
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "requestCell", for: indexPath) as? requestCell
cell!.button.isEnabled = true
// cell!.button.setTitle("Accept", for: UIControl.State())
let userProfileImageURLFirebaseReturn = item.userImageURL
let userNameTagFirebaseReturn = item.nametag
let userNameFirebaseReturn = item.username
let imageURL = userProfileImageURLFirebaseReturn
// self.urlContentArray.append(imageURL)
// guard imageURL != nil && imageURL != "" else {return}
if imageURL != nil && userProfileImageURLFirebaseReturn != nil && userProfileImageURLFirebaseReturn != "" && imageURL != "" {
let resource = ImageResource(downloadURL: URL(string: imageURL!)!, cacheKey: userProfileImageURLFirebaseReturn)
cell?.userProfileImage.kf.setImage(with: resource)
cell?.usernameLbl.text = userNameFirebaseReturn
cell?.userNameTagLbl.text = userNameTagFirebaseReturn
};
// cell?.userProfileImage.kf.setImage(with: resource)
cell?.usernameLbl.text = userNameFirebaseReturn
cell?.userNameTagLbl.text = userNameTagFirebaseReturn
//cell?.button.backgroundColor = #colorLiteral(red: 1, green: 0.3354814752, blue: 0.289293822, alpha: 1)
cell!.setFunction {
cell!.button.isEnabled = true
let id = item.userUID
FriendSystem.system.acceptFriendRequest(id!)
}
return cell!
default:
return UITableViewCell();
}},
titleForHeaderInSection: { dataSource, index in
return dataSource.sectionModels[index].header
});
dataSource.animationConfiguration = AnimationConfiguration(insertAnimation: .fade, reloadAnimation: .fade, deleteAnimation: .fade);
******* THIS IS HOW THE ARRAY IS BEING UPDATED AND BEING PULLED IN WITH A FIREBASE OBSERVER IN THE VIEWDIDLOAD *******
var requestList = user
var requestListUser = [String]()
/** Adds a friend request observer. The completion function will run every time this list changes, allowing you
to update your UI. */
func addRequestObserver(_ update: #escaping () -> Void) {
let ref = USER_REF.child((Auth.auth().currentUser?.uid)!).child("requests");
ref.keepSynced(true);
ref.observe(DataEventType.value, with: { (snapshot) in
guard (Auth.auth().currentUser?.uid) != nil else { return }
self.requestList.removeAll()
self.requestListUser.removeAll()
for child in snapshot.children.allObjects as! [DataSnapshot] {
let id = child.key
FriendSystem.system.getCurrentUser({ (userDataReturned) in
if userDataReturned.email != nil && userDataReturned.userImageURL != nil &&
userDataReturned.nametag != nil &&
userDataReturned.username != nil &&
userDataReturned.userUID != nil {
self.requestListUser.append(id);
self.getUser(id, completion: { (user) in
self.requestList.append(user)
update()
});
} else {
print("User request account had an account not completely populated")
}
})
// self.requestListUser.append(id)
// self.getUser(id, completion: { (user) in
// self.requestList.append(user)
// update()
// })
}
// If there are no children, run completion here instead
if snapshot.childrenCount == 0 {
update()
}
})
}
**** IN VIEWDIDLOAD. ****
//THIS adds an observer and fills the userList array
FriendSystem.system.addUserObserver {
}

Related

I have 2 view controllers with same logic but one of them is not working

I have 2 view models TransferViewModel which has the respective TransferViewController for making Local Transactions from a model LocalTransactionRequest and i have BankTransferViewModel which has a model BankTransactionsRequest, the first one is working but the second one is not, both view controllers are supposed to perform segue to another view controller ConfirmViewController, but the second one (BankTransferViewController) is not working
[This one is TransferViewController][1]
private func setupViewModel() {
viewModel.isTransfer = isTransfer
viewModel.loan = loan
viewModel.getBalance()
transferButton.rx.tap.asObservable().subscribe(onNext: { [weak self] _ in
guard let strongSelf = self else { return }
if let isVerified = UserManager.shared.get()?.IsVerified.value, isVerified{
strongSelf.viewModel.phoneNumberText.accept(strongSelf.phoneNumberTextField.text ?? "")
strongSelf.viewModel.amountText.accept(strongSelf.amountTextField.text ?? "")
strongSelf.viewModel.transfer()
}else{
strongSelf.showVerificationAlert()
}
}).disposed(by: disposeBag)
viewModel.accountInfo.asObservable().subscribe(onNext: { [weak self] accountInfo in
if let account = accountInfo{
guard let strongSelf = self else { return }
strongSelf.accountInfo = account
let request = LocalTransactionRequest(Identification: UserManager.shared.identification ?? "", Amount: Double(strongSelf.amountTextField.text!)!, ReceiverPhoneNumber: strongSelf.phoneNumberTextField.text!, IDBankAccount: UserManager.shared.defaultBankAccountId ?? -1, IsFromTransfer: strongSelf.isTransfer, Description: strongSelf.descriptionTF.text!)
strongSelf.transferRequest.accept(request)
strongSelf.performSegue(withIdentifier: "segue_toConfirmTransfer", sender: account)
}
}).disposed(by: disposeBag)
}
[This one is BankTransferViewController][2]
private func setupViewModel(){
viewModel.isTransfer = isTransfer
viewModel.getBalance()
transferButton.rx.tap.asObservable().subscribe(onNext: { [weak self] _ in
guard let strongSelf = self else { return }
if let isVerified = UserManager.shared.get()?.IsVerified.value, isVerified{
strongSelf.viewModel.bankNumberText.accept(strongSelf.bankNumberTextField.text ?? "")
strongSelf.viewModel.firstName.accept(strongSelf.firstNameTextField.text ?? "")
strongSelf.viewModel.lastName.accept(strongSelf.lastNameTextField.text ?? "")
strongSelf.viewModel.amountText.accept(strongSelf.amountTextField.text ?? "")
strongSelf.viewModel.descriptionText.accept(strongSelf.descriptionTF.text ?? "")
strongSelf.viewModel.transferNational()
}else{
strongSelf.showVerificationAlert()
}
}).disposed(by: disposeBag)
viewModel.transferRequest.asObservable().subscribe(onNext: { [weak self] bankRequest in
if let bank = bankRequest{
guard let strongSelf = self else { return }
strongSelf.bankTransferRequest = bank
let request = BankTransactionRequest(Identification: UserManager.shared.identification ?? "", ReceiverBankAccount: strongSelf.bankNumberTextField.text!, ReceiverFirst: strongSelf.firstNameTextField.text!, ReceiverLast: strongSelf.lastNameTextField.text!, Amount: Double(strongSelf.amountTextField.text!)!, Description: strongSelf.descriptionTF.text!)
strongSelf.nationalTransferRequest.accept(request)
DispatchQueue.main.async {
strongSelf.performSegue(withIdentifier: "segue_toConfirmTransfer", sender: bank)
}
}
}).disposed(by: disposeBag)
}
This is view model of BankTransferViewController
import RxCocoa
import RxSwift
class BankTransferViewModel: BaseViewModel {
private let transferUseCase: TransferUseCase
var accountInfo: BehaviorRelay<AccountExistModel?> = BehaviorRelay(value: nil)
var balance: BehaviorRelay<BalanceModel?> = BehaviorRelay(value: nil)
var bankNumberText: BehaviorRelay<String> = BehaviorRelay(value: "")
var firstName: BehaviorRelay<String> = BehaviorRelay(value: "")
var lastName: BehaviorRelay<String> = BehaviorRelay(value: "")
var amountText: BehaviorRelay<String> = BehaviorRelay(value: "")
var descriptionText: BehaviorRelay<String> = BehaviorRelay(value: "")
var transferRequest: BehaviorRelay<BankTransactionRequest?> = BehaviorRelay(value: nil)
var accountExist = PublishSubject<Bool>()
var hasMoney = PublishSubject<Bool>()
var invalidBankNumber = PublishSubject<Bool>()
var accountCannotRecieve = PublishSubject<Bool>()
var isTransfer : Bool = true
var transferPressed: AnyObserver<Void> {
return AnyObserver { [weak self] event in
switch event {
case .next:
guard let strongSelf = self else {
return
}
strongSelf.checkValidation()
default:
break
}
}
}
init(transferUseCase: TransferUseCase) {
self.transferUseCase = transferUseCase
}
func transferNational() {
self.checkValidation()
}
private func checkValidation() {
guard let balance = self.balance.value else {
state.onNext(.error(error: RepoError(with: "Dështoi verifikimi i disponueshmërisë financiare. Ju lusim të provoni më vonë.")))
return
}
if bankNumberText.value == ""{
state.onNext(.error(error: RepoError(with: "Plotëso fushën për numrin e bankës të pranuesit.")))
return
}
if bankNumberText.value.count < 6{
state.onNext(.error(error: RepoError(with:"Ju lutemi, shtypni një numër valid të gjirollogarisë")))
return
}
guard let doubleAmount = Double(amountText.value), doubleAmount > 0 else {
state.onNext(.error(error: RepoError(with: "Shuma jo e rregullt")))
return
}
if amountText.value == ""{
state.onNext(.error(error: RepoError(with: "Shuma jo e
saktë.")))
return
}
if balance.Balance < doubleAmount{
state.onNext(.error(error: RepoError(with: "Nuk keni fonde të mjaftueshme për realizimin e transaksionit.")))
return
}
if bankNumberText.value != "" && amountText.value != "" && (balance.Balance >= doubleAmount) {
// checkAccountExist()
}
}
func checkModulus16(accountNumber: String) -> Bool {
if accountNumber.isEmpty{
return false
}
let newValue = accountNumber.dropLast(2)
let mod = Int64(newValue + "00")! % 97
let result = 98 - mod
let derivedData = newValue + "" + (result < 10 ? "0\(result)" : "\(result)")
return Int64(derivedData) == Int64(accountNumber)
}
func showError(with message: String ) {
state.onNext(.error(error: RepoError(with: message)))
}
func getBalance(){
let params = ["Identification": UserManager.shared.identification ?? "" ] as ApiJson
transferUseCase.getBalance(with: params) {[weak self] (balance, error) in
guard let strongSelf = self else { return }
if let error = error {
strongSelf.state.onNext(.error(error: error))
strongSelf.accountExist.onNext(false)
}else if let balance = balance{
UserManager.shared.userBonus = balance.BonusAmount
strongSelf.state.onNext(.content)
strongSelf.balance.accept(balance)
strongSelf.accountExist.onNext(true)
UserManager.shared.updateBalance(with: balance)
}
}
}
//MARK: - baseViewModel
override func tryAgain() {
self.getBalance()
}
}
Make sure the following points are valid for your performSegue to work in BankTransferViewController:
The BankTransferViewController has a segue pointing to ConfirmViewController.
The identifier in your performSegue(withIdentifier: yourIdentifier, sender: yourModel) is the exact same identifier as the segue in storyboard that is connecting the two view controllers.
Since you are using it inside the viewModel.transferRequest.asObservable().subscribe(onNext: code, make sure you are emmiting a value to viewModel.transferRequest somewhere in the code. Otherwise, performSegue will never get called.
Since you have this check if let bank = bankRequest{ before using performSegue, make sure the transferRequest value you emmit is not nil.

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

Indexpath.row repeat lead to intermittent Index out of range error

When tableview is first loaded, the index print(indexPath.row) shows index 0,1,2. When the tableview is loaded again the indexpath repeats itself 3 times, in the debugger it will be 0,1,2,0,1,2,0,1,2. This happens within two seconds, but if you scroll the tableview before this there is a fatal error: Index out of range error.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! EstablishmentCell
let object = Model.sharedInstance.items[indexPath.row]
cell.venueDistance.text = object.venueDistance
cell.titleLabel.text = object.name
object.loadCoverPhoto { image in
dispatch_async(dispatch_get_main_queue()) {
cell.coverPhotoView.image = image
}
}
let myCustomSelectionColorView = UIView()
myCustomSelectionColorView.backgroundColor = UIColor(red:0.16, green:0.65, blue:0.64, alpha:1.0)
cell.selectedBackgroundView = myCustomSelectionColorView
}
}self.activityIndicatorView.stopAnimating()
return cell
}}
EDIT1:
Establishment Class
class Establishment: NSObject {
//Properties
var record: CKRecord!
var name: String!
var establishmentDescription: String!
var establishmentOpening: String!
var venueLocation: CLLocation!
weak var database: CKDatabase!
var assetCount = 0
var establishmentDistance: String!
let locationManager = CLLocationManager()
//Map Annotation Properties
// var coordinate: CLLocationCoordinate2D {
// return venueLocation.coordinate
// }
var title: String? {
return name
}
var venueDescription: String? {
return establishmentDescription
}
var venueDistance: String? {
return establishmentDistance
}
//Initializers
init(record: CKRecord, database: CKDatabase) {
self.record = record
self.database = database
//let venueLocation = record["Location"] as? CLLocation
//let location = CLLocation()
//let userLocation = CLLocation(latitude: 51.211963, longitude: -0.769298)
self.name = record["Name"] as? String
self.establishmentDescription = record["Description"] as? String
self.establishmentOpening = record["OpeningTimes"] as? String
self.venueLocation = record["Location"] as? CLLocation
let location = locationManager.location
let distanceBetween: CLLocationDistance = (venueLocation!.distanceFromLocation(location!))
self.establishmentDistance = String(format: "%.f", distanceBetween)
}
func fetchPhotos(completion: (assets: [CKRecord]!) ->()) {
let predicate = NSPredicate(format: "Establishment == %#", record)
let query = CKQuery(recordType: "EstablishmentPhoto", predicate: predicate)
// Intermediate Extension Point - with cursors
database.performQuery(query, inZoneWithID: nil) { [weak self] results, error in
defer {
completion(assets: results)
}
guard error == nil,
let results = results else {
return
}
self?.assetCount = results.count
}
}
func loadCoverPhoto(completion:(photo: UIImage!) -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
var image: UIImage!
defer {
completion(photo: image)
}
guard let asset = self.record["CoverPhoto"] as? CKAsset,
path = asset.fileURL.path,
imageData = NSData(contentsOfFile: path) else {
return
}
image = UIImage(data: imageData)
}
}
Model Class:
protocol ModelDelegate {
func errorUpdating(error:NSError)
func modelUpdated() class Model{
//Properties
let EstablishmentType = "Establishment"
static let sharedInstance = Model()
var delegate: ModelDelegate?
var items: [Establishment] = []
let userInfo: UserInfo
let locationManager = CLLocationManager()
var latitude : String!
var longitude : String!
var isLoading = Bool()
//Define Databases
// Represents the default container specified in the iCloud section of the Capabilities tab for the project.
let container: CKContainer
let publicDB: CKDatabase
let privateDB: CKDatabase
//Indicator
// Ask for Authorisation from the User.
func requestLocation() {
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.locationManager.distanceFilter = 10
self.locationManager.startUpdatingLocation()
// Check if this app has permission to use location services
let authorizationStatus:CLAuthorizationStatus = CLLocationManager.authorizationStatus()
if authorizationStatus == CLAuthorizationStatus.Denied {
// TODO: Tell user that app functionality may be limited
}
else if authorizationStatus == CLAuthorizationStatus.NotDetermined {
// Manually prompt the user for permission
self.locationManager.requestWhenInUseAuthorization()
}
else if authorizationStatus == CLAuthorizationStatus.AuthorizedWhenInUse {
self.locationManager.startUpdatingLocation()
}
}
//Initializers
init () {
container = CKContainer.defaultContainer()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
userInfo = UserInfo(container: container)
}
#objc func refresh() {
let location = locationManager.location
let radius = CGFloat(1000)
let predicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K,%#) < %f", "Location", location!, radius)
let query = CKQuery(recordType: "Establishment", predicate: predicate)
let sort = CKLocationSortDescriptor(key: "Location", relativeLocation: location!)
query.sortDescriptors = [sort]
publicDB.performQuery(query, inZoneWithID: nil) { [unowned self] results, error in
guard error == nil else {
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.errorUpdating(error!)
print("Cloud Query Error - Refresh: \(error)")
}
return
}
self.items.removeAll(keepCapacity: true)
for record in results! {
let establishment = Establishment(record: record, database: self.publicDB)
self.items.append(establishment)
}
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.modelUpdated()
}
}
}
func establishment(ref: CKReference) -> Establishment! {
let matching = items.filter { $0.record.recordID == ref.recordID }
return matching.first
}}
Mention all datasource method here which are added in your code .
And also check your following method :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return Model.sharedInstance.items.count
}

Check For Empty Array From JSON

I am trying to get an array of strings from JSON and I'm trying to figure out how to deal with it if the returned array is empty. In some cases, the returned value is [] and for other cases, the array contains string values. It is crashing because of unexpectedly finding a nil value.
For clarification, the gyms array is passed from another class and everything here works without the code for the images.
Here is my relevant code:
var gyms = [AnyObject]()
var imageArrays = [[String]?]()
In viewDidLoad()
getGymImages()
Methods to get JSON data:
func getGymImages() {
var index = 0
for dictionary in gyms {
let id = dictionary["id"] as! String
let urlString = String("https://gyminyapp.azurewebsites.net/api/GymImage/\(id)")
let url = NSURL(string: urlString)
let data = NSData(contentsOfURL: url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
for imageArray in json as! [AnyObject] {
imageArrays.append((imageArray as? [String])!)
}
} catch {
print("Error")
}
index += 1
}
addImagesToGyms()
}
func addImagesToGyms() {
var index = 0;
for array in imageArrays {
var dictionary = gyms[index] as! [String:AnyObject]
dictionary["images"] = array
gyms[index] = dictionary
index += 1
}
}
In cellForRowAtIndexPath()
let gymImages = dictionary["images"] as! [String]
if gymImages.count > 0 {
let firstImageURL = gymImages[0] as String
cell.cellImageView.sd_setImageWithURL(NSURL(string: firstImageURL))
}
EDIT: I was asked to show more of the file, so here it is.
import UIKit
class GymListTableViewController: UITableViewController {
var gyms = [AnyObject]()
var gymName: String?
var gymAddress: String?
var gymPhoneNumber: String?
var gymWebsite: String?
var gymID: String?
var gymLatitude: String?
var gymLongitude: String?
var maxDistance: Double?
var myLocation: CLLocation?
var milesArray = [Double]()
var imageArrays = [[String]?]()
var segmentedControl: UISegmentedControl?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Gyms"
tableView.registerNib(UINib(nibName: "GymListTableViewCell", bundle: nil), forCellReuseIdentifier: "gymCell")
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "waypoint_map"), style: .Done, target: self, action: #selector(showMapView))
self.navigationItem.rightBarButtonItem?.tintColor = BarItems.greenTintColor
segmentedControl = UISegmentedControl(items: ["A-Z", "Z-A", "Rating", "Distance"])
segmentedControl?.sizeToFit()
segmentedControl?.selectedSegmentIndex = 0
segmentedControl!.setTitleTextAttributes([NSFontAttributeName: UIFont(name:"Helvetica-Light", size: 15)!],
forState: UIControlState.Normal)
segmentedControl?.addTarget(self, action: #selector(changeSelectedSegmentIndex), forControlEvents: .ValueChanged)
self.navigationItem.titleView = segmentedControl
sortAlphabetically()
let backgroundImage = UIImage(named: "gray_background")
let backgroundImageView = UIImageView(image: backgroundImage)
tableView.backgroundView = backgroundImageView
addDistancesToGyms()
getGymImages()
// geocodeAddresses()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func addDistancesToGyms() {
var index = 0
for distance in milesArray {
var dictionary = gyms[index] as! [String:AnyObject]
dictionary["distance"] = distance
gyms[index] = dictionary
index += 1
}
}
func getGymImages() {
var index = 0
for dictionary in gyms {
let id = dictionary["id"] as! String
let urlString = String("https://gyminyapp.azurewebsites.net/api/GymImage/\(id)")
let url = NSURL(string: urlString)
let data = NSData(contentsOfURL: url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
for imageArray in json as! [AnyObject] {
imageArrays.append((imageArray as? [String])!)
}
} catch {
print("Error")
}
index += 1
}
addImagesToGyms()
}
func addImagesToGyms() {
var index = 0;
for array in imageArrays {
var dictionary = gyms[index] as! [String:AnyObject]
dictionary["images"] = array
gyms[index] = dictionary
index += 1
}
}
func changeSelectedSegmentIndex() {
let segmentTouched = segmentedControl?.selectedSegmentIndex
if segmentTouched == 0 {
sortAlphabetically()
} else if segmentTouched == 1 {
sortReverseAlphabetically()
} else if segmentTouched == 2 {
sortByRatingAscending()
} else {
sortByDistanceAscending()
}
}
func sortAlphabetically() {
gyms.sortInPlace{
(($0 as! Dictionary<String, AnyObject>)["name"] as? String) < (($1 as! Dictionary<String, AnyObject>)["name"] as? String)
}
tableView.reloadData()
}
func sortReverseAlphabetically() {
gyms.sortInPlace{
(($0 as! Dictionary<String, AnyObject>)["name"] as? String) > (($1 as! Dictionary<String, AnyObject>)["name"] as? String)
}
tableView.reloadData()
}
func sortByRatingAscending() {
// TODO: Sort by rating
}
func sortByDistanceAscending() {
gyms.sortInPlace{
(($0 as! Dictionary<String, AnyObject>)["distance"] as? Double) < (($1 as! Dictionary<String, AnyObject>)["distance"] as? Double)
}
tableView.reloadData()
}
func showMapView() {
self.performSegueWithIdentifier("displayMapSegue", sender: self.navigationController)
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gyms.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 131
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("gymCell", forIndexPath: indexPath) as! GymListTableViewCell
let dictionary = gyms[indexPath.row]
let addressDictionary = dictionary["address"]
let street = addressDictionary!!["streetAddress"] as! String
let city = addressDictionary!!["city"] as! String
let state = addressDictionary!!["state"] as! String
let zipInt = addressDictionary!!["zipCode"] as! Int
let zipCode = String(zipInt)
let addressString = String("\(street) " + "\(city), " + "\(state) " + "\(zipCode)")
cell.backgroundColor = UIColor.clearColor()
cell.gymNameLabel.text = dictionary["name"] as? String
cell.gymAddressLabel.text = addressString
let miles = dictionary["distance"] as! Double
let milesString = String(format: "%.1f miles", miles)
let milesLabelString = milesString
cell.milesLabel.text = milesLabelString
let gymImages = dictionary["images"] as! [String]
if gymImages.count > 0 {
let firstImageURL = gymImages[0] as String
cell.cellImageView.sd_setImageWithURL(NSURL(string: firstImageURL))
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let dictionary = gyms[indexPath.row]
if dictionary["name"] as? String != nil {
self.gymName = dictionary["name"] as? String
}
let cell = tableView.cellForRowAtIndexPath(indexPath) as! GymListTableViewCell
self.gymAddress = cell.gymAddressLabel.text
if dictionary["phone"] as? String != nil {
self.gymPhoneNumber = dictionary["phone"] as? String
}
if dictionary["website"] as? String != nil {
self.gymWebsite = dictionary["website"] as? String
}
if dictionary["id"] as? String != nil {
self.gymID = dictionary["id"] as? String
}
if dictionary["latitude"] as? String != nil {
self.gymLatitude = dictionary["latitude"] as? String
}
if dictionary["longitude"] as? String != nil {
self.gymLongitude = dictionary["longitude"] as? String
}
self.performSegueWithIdentifier("detailFromListSegue", sender: self.navigationController)
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailFromListSegue" {
let gymDetailVC = segue.destinationViewController as! DetailTableViewController
if self.gymName != nil {
gymDetailVC.gymName = self.gymName
} else {
gymDetailVC.gymName = nil
}
if self.gymAddress != nil {
gymDetailVC.gymAddress = self.gymAddress
} else {
gymDetailVC.gymAddress = nil
}
if self.gymPhoneNumber != nil {
gymDetailVC.gymPhoneNumber = self.gymPhoneNumber
} else {
gymDetailVC.gymPhoneNumber = nil
}
if self.gymWebsite != nil {
gymDetailVC.gymWebsite = self.gymWebsite
} else {
gymDetailVC.gymWebsite = nil
}
if self.gymID != nil {
gymDetailVC.gymID = self.gymID!
} else {
// gymDetailVC.gymID = nil
}
if self.gymLatitude != nil {
gymDetailVC.gymLatitude = self.gymLatitude!
}
if self.gymLongitude != nil {
gymDetailVC.gymLongitude = self.gymLongitude!
}
}
}
}
numberOfRowsInSection should be returning gymImages.count if it isn't already.
Then as a safeguard you can always do
if indexPath.row < gymImages.count {
}
before accessing the content in cellForRowAtIndexPath

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