Map Object into 2D Array Swift for TableView Sections - ios

I could not figure out a better way of doing this. I am mapping all the properties of the Student Object into a 2D Array. So my TV has sections.
I cannot use a Static Tableview either, if so this problem would not exist.
So my code in the TVC
let currentUser = PFUser.currentUser()! as! MyUser
var membershipSection:[[String:String]]!
var detailsSection:[[String:String]]!
var emergancySection:[[String:String]]!
var medicalSection:[[String:String]]!
var titlesForSection = ["MEMBERSHIP", "DETAILS", "EMERGANCY CONTACT", "MEDICAL HISTORY"]
var combo = [[[String:String]]]() // Data Source for TableView
// The following is called from ViewDidLoad
func loadDisplayDataSource() {
combo.removeAll(keepCapacity: true)
var idString = "Awaiting ID Generation"
if student.objectId != nil {
idString = student.objectId!
}
membershipSection = [["Sessions":student.sessionsRemaining], ["Details":""], ["ID":idString]]
detailsSection = [["First Name":student.firstName], ["Last Name":student.lastName], ["DOB":""], ["Address":""], ["Phone":""], ["Email":student.email], ["Occupation":""]]
emergancySection = [["Name":""], ["Phone":""]]
medicalSection = [["Recent Surgery":""], ["Hypertension":""], ["Diabetes":""], ["Caradic":""], ["Epilesy":""], ["Syncope":""], ["Medications":""], ["Medical Details":""], ["Other Injuries":""]]
combo.append(membershipSection)
combo.append(detailsSection)
combo.append(emergancySection)
combo.append(medicalSection)
self.tableView.beginUpdates()
var range = NSMakeRange(0, self.numberOfSectionsInTableView(self.tableView))
var sections = NSIndexSet(indexesInRange: range)
self.tableView.deleteSections(sections, withRowAnimation: UITableViewRowAnimation.None)
self.tableView.insertSections(sections, withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.endUpdates()
}
Is there a better way to map a object's data into sections ? The way I'm doing it works, but is a little confusing. If i could use a static view this would be easier, but I cannot as using a drop in TV within a Normal VC and you cannot use static TV in these. Which is annoying! Is there a cleaner way?
Can I make this more SWIFTY - A better way to create my combo data source.
Thanks for any advice.
My end result - which is working looks like this - A TVC with sections.

I'm not entirely sure what you're asking. What is 'combo' used for?
If you want to just package up your data in a cleaner fashion, structs in Swift are nice for this. Something like:
struct EmergencySection{
var name: String!
var phone: String!
}
//then to instantiate in loadDisplayDataSource
var emergencySection = EmergencySection(name: "", phone: "")
combo.append(emergencySection)

Try using RETableViewManager, it's pretty awesome for such tasks. Well, it's fully Objective-C, but at least you could have a quick look of it.

How about this?
import UIKit
class
ViewController: UITableViewController {
var combo = [ [ String: AnyObject? ] ]()
let titlesForSection = ["MEMBERSHIP", "DETAILS", "EMERGANCY CONTACT", "MEDICAL HISTORY"]
override func
viewDidLoad() {
super.viewDidLoad()
// Something about studen data
combo = [
[ "Sessions":"student.sessionsRemaining", "Details":"", "ID":"idString" ]
, [ "First Name":"student.firstName", "Last Name":"student.lastName", "DOB":"", "Address":"", "Phone":"", "Email":"student.email", "Occupation":"" ]
, [ "Name":"", "Phone":"" ]
, [ "Recent Surgery":"", "Hypertension":"", "Diabetes":"", "Caradic":"", "Epilesy":"", "Syncope":"", "Medications":"", "Medical Details":"", "Other Injuries":"" ]
]
}
override func
numberOfSectionsInTableView(tableView: UITableView ) -> Int {
return combo.count
}
override func
tableView(tableView: UITableView, numberOfRowsInSection section: Int ) -> Int {
return combo[ section ].count
}
override func
tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return titlesForSection[ section ]
}
override func tableView( tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath ) -> UITableViewCell {
let v = tableView.dequeueReusableCellWithIdentifier( "SomeIdentifier" ) as! UITableViewCell
let w = combo[ indexPath.section ]
let wKey = Array( w.keys )[ indexPath.row ]
v.textLabel!.text = wKey
v.detailTextLabel!.text = w[ wKey ] as? String
return v
}
}

Here is how I am doing it, a bit cleaner
private struct Details {
static let title = "DETAILS"
static let firstName = (key:"First Name", index:0)
static let lastName = (key:"Last Name", index:1)
static let dob = (key:"DOB", index:2)
static let address = (key:"Address", index:3)
static let phone = (key:"Phone", index:4)
static let email = (key:"Email", index:5)
static let occupation = (key:"Occupation", index:6)
static func splitIntoDictionaries(student: Student) -> [[String:String]] {
return [
[firstName.key:student.firstName], // 0
[lastName.key:student.lastName], // 1
[dob.key:""],
[address.key:""],
[phone.key:""],
[email.key:student.email],
[occupation.key:""]
]
}
}

You can use a UITableViewController with static cells in a normal UIViewController by adding it as a child view controller.
parentVC.addChildViewController(childVC)
childVC.view.frame = parentVC.view.bounds
parentVC.view.addSubview(childVC.view)
childVC.didMoveToParentViewController(parentVC)

Related

Not able to sort table view data in ascending order

I have an table view which will populate some data. Now I need to sort my table view data in ascending order.
var SearchedobjectArray = [Objects]()
struct Objects {
var looId : String!
var looName : String
var looImageUrl:String!
var looCategoryType:String!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier:"cell", for: indexPath) as? MyLooCell{
cell.looImage.setShowActivityIndicator(true)
cell.looImage.setIndicatorStyle(.gray)
let imageURL = SearchedobjectArray[indexPath.row].looImageUrl
if (imageURL?.isEmpty)! {
let imageUrl = self.getDefaultImageForCategory(categoryName: SearchedobjectArray[indexPath.row].looCategoryType)
cell.looImage.image = UIImage(named: imageUrl)
} else {
cell.looImage.sd_setImage(with: URL(string: SearchedobjectArray[indexPath.row].looImageUrl))
}
cell.looName.text = SearchedobjectArray[indexPath.row].looName
let looCatType = SearchedobjectArray[indexPath.row].looCategoryType
} else {
return UITableViewCell()
}
}
I tried with : let array = SearchedobjectArray.sorted(by: )
But I am not sure how can I sort this data with ascending order a to z. I tried with other sorted() also but not able to achieve.
When data is fetched in an array then you can simply sort the array on looName basis using the following code.
SearchedobjectArray = SearchedobjectArray.sorted(by: { $0.looName > $1.looName})
tableView.reloadData()
You need to sort your array of objects and then tableView.reloadData(). Here's a Playground example of how to sort your array:
import Cocoa
struct Objects {
var looId : String!
var looName : String
var looImageUrl:String!
var looCategoryType:String!
}
var SearchedobjectArray = [Objects]()
let c = Objects(looId: "Chase", looName: "Chase", looImageUrl: "Chase", looCategoryType: "Chase")
SearchedobjectArray.append(c)
let b = Objects(looId: "Bree", looName: "Bree", looImageUrl: "Bree", looCategoryType: "Bree")
SearchedobjectArray.append(b)
let a = Objects(looId: "Adam", looName: "Adam", looImageUrl: "Adam", looCategoryType: "Adam")
SearchedobjectArray.append(a)
print("Before sorting")
print(SearchedobjectArray)
// The real sorting is happening here...I guessed you wanted to sort by looName
SearchedobjectArray = SearchedobjectArray.sorted(by: { $0.looName < $1.looName })
print("After sorting")
print(SearchedobjectArray)

Swift: How to make a new indexPath for the extra keys of a dictionary

I want the iteration of a dictionary to happen for all keys in it, not just for one in the indexPath.row
struct Whatever {
var title: String
var tag: [String:String?]?
}
var cases = [
Whatever(title: "Name1", tag: ["key1": "value1", "key2":"value2"]),
Whatever(title: "Name2", tag: ["key3": "value3"]
]
Later in the ViewController:
let arrayCases = cases[indexPath.row]
let caseTag = arrayCases.tag!
for key in caseTag.keys {
cell.titleLabel?.text = key
//the magic stops somewhere here
}
for value in caseTag.values {
if value != nil {
cell.txt.text = value
} else {
cell.txt.text = arrayCases.title
}
}
Could you tell me how to make a new indexPath.row for the second tag? As if it's a separate insurance of 'Whatever'?
Second question - why does it show after each build a different tag - sometimes it's "tag1", other times it's "tag2"?
Thank you!
I would add two calculated properties to your struct that returns a list of tag keys and values respectively to make the rest of the code cleaner.
var allTagKeys: String {
if let keys = tag?.keys {
return keys.sorted().joined(separator: ", ")
}
return ""
}
var allTagValues: String {
if let values = tag?.compactMap({ $0.value }) {
return values.joined(separator: ", ")
}
return ""
}
}
Note that I added sorting to the keys, not sure you want that.
If you use a standard table view (without sections) each item in the data source represents one row. You cannot simply make a new indexPath.row.
You have two options:
Use sections: One Whatever is one section, the title is the header, each tag is one row (see code below)
Concatenate the tag keys and values
cell.titleLabel?.text = caseTag.keys.joined(separator: ", ")
cell.txt.text = caseTag.values.joined(separator: ", ")
Regarding second question: Dictionaries are unordered, there is no order. If you need a specific order use another struct Tag and make tags an array for example
struct Whatever {
let title: String
let tags: [Tag]
}
struct Tag {
let key, value : String
}
let cases = [
Whatever(title: "Name1", tags: [Tag(key: "key1", value: "value1"), Tag(key: "key2", value: "value2")]),
Whatever(title: "Name2", tags: [Tag(key: "key3", value: "value3"), Tag(key: "key4", value: "value4")])
]
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let case = cases[section]
return case.title
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
let section = cases[indexPath.section]
let case = section.tags[indexPath.row]
cell.titleLabel?.text = case.key
cell.txt.text = case.value

Variable from viewDidLoad not populating custom table cell

I need to take variables that are populated in the viewDidLoad method to show up on labels connected to a custom cell. What i am trying to do is:
Find out SKUs in user's box stored in database
Use SKU to find out details of the product stored in database
Store product details in appropriate variable
Take said variable and populate labels in a custom table cell
The issue is that I can store the variable in the viewDidLoad method, but when I try to call the variable to populate the custom table cell, the variable is blank.
I am using Firebase to store the data. The fire base nodes are set up as the following, Node 1: Products/Sku/Item details Node 2: Box/UID/Skus
"products" : {
"0123456" : {
"brand" : "Nike",
"item_name" : "basketball"
}
},
"box" : {
"jEI5O8*****UID" : {
"sku" : "0123456"
I've been scouring through stack overflow, youtube, google, etc but i can't seem to find a solution...If you can help point me in the right direction that would be greatly appreciated! FYI I am new to swift/firebase.
import UIKit
import FirebaseAuth
import FirebaseDatabase
class drawerFaceExampleViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
var databaseRef = FIRDatabase.database().reference()
var loggedInUser = AnyObject?()
var loggedInUserData = AnyObject?()
var itemDrawer = AnyObject?()
var dataDict = AnyObject?()
#IBOutlet weak var homeTableView: UITableView!
var item_name = String()
var brand_name = String()
override internal func viewDidLoad() {
super.viewDidLoad()
self.loggedInUser = FIRAuth.auth()?.currentUser
//get the logged in users details
self.databaseRef.child("user_profiles").child(self.loggedInUser!.uid).observeSingleEventOfType(.Value) { (snapshot:FIRDataSnapshot) in
//store the logged in users details into the variable
self.loggedInUserData = snapshot
//get all the item sku's that are in the user's box
self.databaseRef.child("box/\(self.loggedInUser!.uid)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
let sku = snapshot.value! as! String
//access the 'products' node to extract all the item details
self.databaseRef.child("products").child(sku).observeSingleEventOfType(.Value, withBlock: { (snapshot:FIRDataSnapshot) in
if let itemvariable = snapshot.value!["item"] as? String {
self.item_name = item variable
//testing to see if item name is stored, works!
print("testing=", self.item_name)
}
if let brandvariable = snapshot.value!["brand"] as? String{
self.brand_name = brand variable
//testing to see if brand name is stored, works!
print("testingBrand =", self.brand_name)
}
})
self.homeTableView.insertRowsAtIndexPaths([NSIndexPath(forRow:0,inSection:0)], withRowAnimation: UITableViewRowAnimation.Automatic)
}){(error) in
print(error.localizedDescription)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: drawerFaceExampleTableViewCell = tableView.dequeueReusableCellWithIdentifier("drawerFaceExampleCell", forIndexPath: indexPath) as! drawerFaceExampleTableViewCell
//checking to see the item & brand name has been extracted...but blank :(
print("item_name=",self.item_name)
print("item_name=",self.item_name)
//this is where item & brand name extracted from viewDidLoad to display in the cell.
cell.configure(nil, brandName: brand_name, itemName: item_name)
return cell
}
}
Sounds like your data hasn't finished loading yet when you go to read the variable. You need to update your UI after the download is complete, in the completion handler:
if let itemvariable = snapshot.value!["item"] as? String {
self.item_name = item variable
//testing to see if item name is stored, works!
print("testing=", self.item_name)
}
if let brandvariable = snapshot.value!["brand"] as? String{
self.brand_name = brand variable
//testing to see if brand name is stored, works!
print("testingBrand =", self.brand_name)
}
// Update UI here.

ReloadData not working Swift with Alamofire

I tried to reload my UITableView after adding new items. When I try with a reloadData() it's not working. Nothing is shown.
If I try to reload my getallrecords function, that reload items but they are repeated.
My source code is :
class FriendsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
#IBOutlet var tabeview: UITableView!
var textArray: NSMutableArray! = NSMutableArray()
var subArray: NSMutableArray! = NSMutableArray()
let defaults = NSUserDefaults.standardUserDefaults()
var valueToPass:String!
var reports_d:String!
var reports:String!
#IBOutlet var menuButton: UIBarButtonItem!
#IBOutlet var friends_icon: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
tabeview.dataSource = self
tabeview.delegate = self
tabeview.emptyDataSetSource = self
tabeview.emptyDataSetDelegate = self
tabeview.tableFooterView = UIView()
getallrecords()
self.tabeview.addPullToRefresh({ [weak self] in
// refresh code
self!.getallrecords()
self?.tabeview.stopPullToRefresh()
})
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.textArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell")
cell.textLabel?.text = self.textArray.objectAtIndex(indexPath.row) as? String
cell.detailTextLabel?.text = self.subArray.objectAtIndex(indexPath.row) as? String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
valueToPass = currentCell.textLabel!.text
reports = reports_d
performSegueWithIdentifier("friends_details", sender: self)
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from your array and updating the tableview)
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
let friend2 = currentCell.textLabel!.text
let defaults = NSUserDefaults.standardUserDefaults()
let username = defaults.objectForKey("name") as! String
Alamofire.request(.GET, "http://www.example.com/app/remove_friends.php", parameters: ["key_id": "xxxxx","user_id": username,"friend_receive_id": friend2!, "action": "delete"])
.response { request, response, data, error in
print(request)
print(response)
print(error)
if(error == nil)
{
self.tabeview.beginUpdates()
self.textArray.removeObjectAtIndex(indexPath.row)
self.subArray.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
self.tabeview.endUpdates()
}
}
NSNotificationCenter.defaultCenter().postNotificationName("reloadData",object: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "friends_details") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destinationViewController as! DetailsFriendsViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
viewController.reports = reports
}
}
func getallrecords(){
if(defaults.stringForKey("name") != nil ){
let username = defaults.objectForKey("name") as! String
let full = "http://www.example.com/app/danger_friend_view.php?search=true&username=" + username
let url = NSURL(string: full)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
do {
let d = NSString(data: data!, encoding: NSUTF8StringEncoding)
var arr = d!.componentsSeparatedByString("<") // spliting the incoming string from "<" operator because before that operator is our required data and storing in array
let dataweneed:NSString = arr[0] as NSString // arr[0] is the data before "<" operator and arr[1] is actually no use for us
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
SwiftSpinner.hide()
do {
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
self.textArray.addObject(info)
self.subArray.addObject(name)
}
self.tabeview.reloadData()
}
} catch let error as NSError {
print(error.localizedDescription)
}
})
}
}
task.resume()
}
else
{
//Do something
}
}
#IBAction func reload_data(sender: UIButton) {
let banner = Banner(title: NSLocalizedString("RELOAD_DATA_TITLE",comment:"I'm in danger, I'm currently at "), subtitle: NSLocalizedString("RELOAD_DATA",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:52.00/255.0, green:152.00/255.0, blue:219.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
dispatch_async(dispatch_get_main_queue()) {
//Not working ....
self.tabeview.reloadData()
}
}
func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let str = "Oups"
let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)]
return NSAttributedString(string: str, attributes: attrs)
}
func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let str = NSLocalizedString("NO_FRIENDS_TO_SHOW",comment:"No friends to show ")
let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleBody)]
return NSAttributedString(string: str, attributes: attrs)
}
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
return UIImage(named: "no-friends")
}
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
let str = NSLocalizedString("ADD_FRIENDS",comment:"Add a friend ")
let attrs = [NSFontAttributeName: UIFont(name: "HelveticaNeue-Light", size: 19)!]
return NSAttributedString(string: str, attributes: attrs)
}
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
let alert = SCLAlertView()
let txt = alert.addTextField("Friend's username")
alert.addButton("Add") {
if(txt.text=="")
{
let banner = Banner(title: NSLocalizedString("ERROR_NO",comment:"An error occured"), subtitle: NSLocalizedString("ERROR_NO_TEXT",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:152.00/255.0, green:52.00/255.0, blue:52.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
}
else
{
let defaults = NSUserDefaults.standardUserDefaults()
let username = defaults.objectForKey("name") as! String
let remove_friend_username = txt.text! as String
Alamofire.request(.GET, "http://www.example.com/add_friends.php", parameters: ["key_id": "xxx","user_id": username,"friend_receive_id": remove_friend_username, "action": "add"])
.response { request, response, data, error in
dispatch_async(dispatch_get_main_queue()) {
self.tabeview.reloadData()
//Not working
}
}
}
}
alert.showEdit("Add friend", subTitle: "You can add a friend by enter his username")
}
}
I believe you are missing a little point in here buddy :)
Question 1
Why reloading tableView wont show new data ??
Your function reload_data is doing nothing more than reloading data buddy :) When you call reload data all the tableView delegates like number of rows in section,number of sections and cellForRowAtIndexPath gets called but all these methods return the value depending on the data source you provide isn't it buddy :)
So if you change the data source and then call reload data they will show you the new data :) but in your reload_data function you are not altering the data source at all :) simply calling reload data on the unalterred data source will re render the tableView again thats all :)
What you can do :)
You already have a method that fetches the new data using almofire :) just call it and in the success block anyway you are reloading the tableView :) So everything will be fine buddy :)
#IBAction func reload_data(sender: UIButton) {
let banner = Banner(title: NSLocalizedString("RELOAD_DATA_TITLE",comment:"I'm in danger, I'm currently at "), subtitle: NSLocalizedString("RELOAD_DATA",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:52.00/255.0, green:152.00/255.0, blue:219.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
self.getallrecords() //simply call this method this will anyhow will reload data on success :)
}
Question 2
Why my tableView shows duplicate data???
Your tableView always show the data which is there in its datasource :) SO if your tableView is showing duplicate cells that means you have duplicate entry in your data source :)
You are dealing with array, in future you might migrate to coredata :)
Understand one thing, when you enter or add a entry to your data source if you dont want to show duplicates you will have to handle it explicitly.
How can I do that ???
From your code I beilieve info(username) value is unique per object. So before blindly adding response to textArray check if text array already consists that object if yes then dont add it again :)
Based on the above stated assumption and believing you are making use of swift 2.0
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
if !self.textArray.contains(info){
self.textArray.addObject(info)
self.subArray.addObject(name)
}
}
self.tabeview.reloadData()
}
Now that's a lot of code, I want a easier solution :)
Clear the array before adding the new response :) Thats all :)
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
self.textArray.removeAll()
self.subArray.removeAll() //clear the arrays and then re populate them thats all no duplicate data anymore :P
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
self.textArray.addObject(info)
self.subArray.addObject(name)
}
self.tabeview.reloadData()
}

Multiple RowTypes in TableView - watchKit

It's rather easy to create a simple TableView with one row type.
You just set
tableView.setNumberOfRows(yourArray.count, withRowType: "yourowtype")
and then add a for loop to fill up your uilabel or whatever you have with data from the array.
When it comes to multiple row types, it's not so clear. I'm aware you have to set
tableView.setRowTypes(yourRowTypesArray)
but i don't understand the rest.
In iOS you have a very clear and straightforward indexPath.row solution in the cellForRowAtIndexPath, where you can say - Okay, i want this array to fill those indexPaths, the other array should fill those e.t.c. with simple IF conditional.
In WatchKit, however, there is no such thing as indexPath.row and it's not clear to me how you can assign specific row numbers for a specific array ? And why should you remove setNumberOfRows (as i've seen in the examples all over the net) in a multiple row type solution?
I've browsed the net heavily regarding the issue and i haven't been able to find a decent workable solution. Just tricks and workarounds.
Thank you.
UPDATE: Adding codes
My arrays
var questionsList = [["[What is the color of?]"],["Which city is the capital of Great Britain", "additional info"],["Some question"]]
var answersList1 = [["Blue"],["London"],["some answer 1"]]
var answersList2 = [["Grey"],["Liverpool"],["some answer 2"]]
The loadTable function
private func loadTable(){
tableView.setRowTypes(rowTypes)
for i in 0 ..< questionsList[0].count {
let rowController = tableView.rowControllerAtIndex(i) as! TableViewRowController
rowController.lblQuestion.setText(questionsList[0][i])
}
let rowController1 = tableView.rowControllerAtIndex(answersList1[0].count) as! AnswerRowController1
rowController1.button1.setTitle(answersList1[0][0])
let rowController2 = tableView.rowControllerAtIndex(answersList2[0].count+1) as! AnswerRowController2
rowController2.button2.setTitle(answersList2[0][0])
}
I would rather suggest you to refine your model. It looks really difficult to understand. Refactor it into class or struct to make it easy to understand.
Here is my approach to refactor it a bit and create a sort of thing that you wanted,
let QuestionRowIdentifier = "QuestionRowIdentifier"
let AnswerRowIdentifier = "AnswerRowIdentifier"
let QuestionSeparatorRowIdentifier = "QuestionSeparatorIdentifier"
protocol QuestionAnswerRowTypes {
var titleLabel: WKInterfaceLabel! { get set }
}
class QuestionRowController: NSObject, QuestionAnswerRowTypes {
#IBOutlet var titleLabel: WKInterfaceLabel!
}
class AnswerRowController: NSObject, QuestionAnswerRowTypes {
#IBOutlet var titleLabel: WKInterfaceLabel!
}
struct Question {
let title: String
let additionalInfo: String?
let answers: [String]
}
let questions = [
Question(title: "What is the color of?", additionalInfo: nil, answers: [
"Blue",
"Gray"
]),
Question(title: "Which city is the capital of Great Britain?", additionalInfo: "additional info", answers: [
"London",
"Liverpool"
]),
Question(title: "Some question?", additionalInfo: nil, answers: [
"some answer 1",
"some answer 2"
])
]
class InterfaceController: WKInterfaceController {
#IBOutlet private var tableView: WKInterfaceTable!
var names = ["Alexander", "Ferdinand", "Jack", "Samuel", "Thompson", "Tony"]
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let rowTypes = getRowTypes()
tableView.setRowTypes(rowTypes)
for i in 0 ..< rowTypes.count {
if let rowController = tableView.rowControllerAtIndex(i) as? QuestionAnswerRowTypes {
rowController.titleLabel.setText(textAtIndex(i)!)
}
}
}
func getRowTypes() -> [String] {
return questions.flatMap { question in
return [
[QuestionRowIdentifier],
Array(count: question.answers.count, repeatedValue: AnswerRowIdentifier),
[QuestionSeparatorRowIdentifier]
].flatMap { $0 }
}
}
func textAtIndex(index: Int) -> String? {
let titles = questions.flatMap { question in
return
[
[Optional.Some(question.title)],
question.answers.map(Optional.Some),
[Optional.None],
]
}.flatMap( { $0 })
return titles[index]
}
}
And here is the end result,

Resources