Swift Firebase Group Messenger Data - Profile Picture and Name - ios

I have a group messenger and am trying to keep users profile image and name up-to-date incase they decide to change their profile image or update their name. The problem is when I am populating the cells, the data is getting mismatched. So everything loads, the image and name, but it is the wrong people getting loaded.
Calling and setting all users (customers,employees, and businesses)
This is setting the users to a data structure
func getCustomerData() {
Database.database().reference().child("user_profiles").observe(.childAdded, with: { snapshot in
self.customerData.append(CustomerData(snapshot: snapshot))
print(snapshot)
print("Printed Customer Data")
})
}
func getEmployeeData() {
Database.database().reference().child("employees").observe(.childAdded, with: { snapshot in
self.employeeData.append(EmployeeData(snapshot: snapshot))
print(snapshot)
print("Printed Employee Data")
})
}
func getBusinessData() {
Database.database().reference().child("Businesses").observe(.childAdded, with: { snapshot in
self.businessData.append(BusinessData(snapshot: snapshot))
print(snapshot)
print("Printed Business Data")
})
}
Data Structure for customers, employees, and business. Same type of structure for all 3
import UIKit
import Firebase
class CustomerData: NSObject {
var customerName: String?
var customerPicture: String?
var customerUID: String?
init(snapshot: DataSnapshot) {
if let dictionary = snapshot.value as? [String: AnyObject] {
customerName = dictionary["name"] as? String
customerUID = dictionary["uid"] as? String
customerPicture = dictionary["profPicString"] as? String
}
}
}
Cell Set Up
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessageCell
cell.chatLogController = self
let customer = customerData[indexPath.item]
let employee = employeeData[indexPath.item]
let business = businessData[indexPath.item]
let message = messages[indexPath.row]
cell.message = message
cell.customer = customer
cell.employee = employee
cell.business = business
setupChatMessageCell(cell,message,customer,employee,business)
if let text = message.text {
cell.textView.text = text
cell.bubbleWidthAnchor?.constant = estimateSizeOfText(text).width + 32
cell.textView.isHidden = false
} else if message.imageUrl != nil {
cell.bubbleWidthAnchor?.constant = 200
cell.textView.isHidden = true
}
cell.playButton.isHidden = message.videoUrl == nil
return cell
}
private func setupChatMessageCell(_ cell: ChatMessageCell, _ message: GroupMessage, _ customer: CustomerData, _ employee: EmployeeData, _ business: BusinessData) {
if message.fromId == Auth.auth().currentUser?.uid {
//outgoing messages
cell.bubbleView.backgroundColor = ChatMessageCell.blueColor
cell.textView.textColor = .white
cell.bubbleLeftAnchor?.isActive = false
cell.bubbleRightAnchor?.isActive = true
cell.profileImageView.isHidden = true
cell.nameLabel.textColor = .gray
cell.nameRightAnchor?.isActive = true
cell.nameLeftAnchor?.isActive = false
cell.nameLabel.text = customer.customerName?.description
//cell.nameLabel.text = message.customerName
} else if message.fromId == business.businessUID?.description {
//incoming messagese
let customerImage = business.businessPicture?.description
cell.profileImageView.loadImageUsingCacheWithUrlString(customerImage!)
cell.profileImageView.isHidden = false
cell.bubbleView.backgroundColor = UIColor(red: 240, green: 240, blue: 240)
cell.textView.textColor = .black
cell.bubbleLeftAnchor?.isActive = true
cell.bubbleRightAnchor?.isActive = false
cell.profileImageView.isHidden = false
cell.nameRightAnchor?.isActive = false
cell.nameLeftAnchor?.isActive = true
cell.nameLabel.textColor = .black
cell.nameLabel.text = business.businessName
} else {
let customerImage = employee.employeePicture?.description
cell.profileImageView.loadImageUsingCacheWithUrlString(customerImage!)
cell.profileImageView.isHidden = false
cell.bubbleView.backgroundColor = UIColor(red: 240, green: 240, blue: 240)
cell.textView.textColor = .black
cell.bubbleLeftAnchor?.isActive = true
cell.bubbleRightAnchor?.isActive = false
cell.profileImageView.isHidden = false
cell.nameRightAnchor?.isActive = false
cell.nameLeftAnchor?.isActive = true
cell.nameLabel.textColor = .black
cell.nameLabel.text = employee.employeeName
}
if let imageUrl = message.imageUrl {
cell.messageImageView.loadImageUsingCacheWithUrlString(imageUrl)
cell.messageImageView.isHidden = false
cell.bubbleView.backgroundColor = .clear
} else {
cell.messageImageView.isHidden = true
}
}
Firebase Group Messages Structure
I need help on how I can match the message "fromId" to the right user. I have 3 different profiles, customers, employees, and businesses. As of now the wrong data is being set for the business and employee messages. The data for the customer is correct which is the first "if else" statement.
How Data is loaded
So as you can see he displayed name and profile picture is different from the name inside the message.

Related

Swift Accessing Data Structure Inside Cell Setup

I am appending a Firebase Data snapshot to a NSObject of items being a "customer", "employee", and "business". Set up like this:
var customerData = [CustomerData]()
var employeeData = [EmployeeData]()
var businessData = [BusinessData]()
func getCustomerData() {
Database.database().reference().child("user_profiles").observe(.childAdded, with: { snapshot in
self.customerData.append(CustomerData(snapshot: snapshot))
})
}
func getEmployeeData() {
Database.database().reference().child("employees").observe(.childAdded, with: { snapshot in
self.employeeData.append(EmployeeData(snapshot: snapshot))
})
}
func getBusinessData() {
Database.database().reference().child("Businesses").observe(.childAdded, with: { snapshot in
self.businessData.append(BusinessData(snapshot: snapshot))
})
}
Data structure is the same for customer, employees, and business as below
import UIKit
import Firebase
class CustomerData: NSObject {
var customerName: String?
var customerPicture: String?
var customerUID: String?
init(snapshot: DataSnapshot) {
if let dictionary = snapshot.value as? [String: AnyObject] {
customerName = dictionary["name"] as? String
customerUID = dictionary["uid"] as? String
customerPicture = dictionary["profPicString"] as? String
}
}
}
I just want to access this snapshot data inside the cell to keep my message details up-to-date, like the profile picture and name. Below is my cell set up:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessageCell
cell.chatLogController = self
let customer = customerData
let employee = employeeData
let business = businessData
let message = messages[indexPath.row]
cell.message = message
cell.customer = customer
cell.employee = employee
cell.business = business
setupChatMessageCell(cell,message,customer,employee,business)
if let text = message.text {
cell.textView.text = text
cell.bubbleWidthAnchor?.constant = estimateSizeOfText(text).width + 32
cell.textView.isHidden = false
} else if message.imageUrl != nil {
cell.bubbleWidthAnchor?.constant = 200
cell.textView.isHidden = true
}
cell.playButton.isHidden = message.videoUrl == nil
return cell
}
private func setupChatMessageCell(_ cell: ChatMessageCell, _ message: GroupMessage, _ customer: CustomerData, _ employee: EmployeeData, _ business: BusinessData) {
if message.fromId == customer.customerUID {
//outgoing messages
cell.bubbleView.backgroundColor = ChatMessageCell.blueColor
cell.textView.textColor = .white
cell.bubbleLeftAnchor?.isActive = false
cell.bubbleRightAnchor?.isActive = true
cell.profileImageView.isHidden = true
cell.nameLabel.textColor = .gray
cell.nameRightAnchor?.isActive = true
cell.nameLeftAnchor?.isActive = false
cell.nameLabel.text = message.name?.description
//cell.nameLabel.text = message.customerName
} else if message.fromId == employee.employeeUID {
//incoming messagese
let customerImage = employee.employeePicture
cell.profileImageView.loadImageUsingCacheWithUrlString(customerImage!)
cell.profileImageView.isHidden = false
cell.bubbleView.backgroundColor = UIColor(red: 240, green: 240, blue: 240)
cell.textView.textColor = .black
cell.bubbleLeftAnchor?.isActive = true
cell.bubbleRightAnchor?.isActive = false
cell.profileImageView.isHidden = false
cell.nameRightAnchor?.isActive = false
cell.nameLeftAnchor?.isActive = true
cell.nameLabel.textColor = .black
cell.nameLabel.text = message.name?.description
} else if message.fromId == business.businessUID {
let customerImage = business.businessPicture
cell.profileImageView.loadImageUsingCacheWithUrlString(customerImage!)
cell.profileImageView.isHidden = false
cell.bubbleView.backgroundColor = UIColor(red: 240, green: 240, blue: 240)
cell.textView.textColor = .black
cell.bubbleLeftAnchor?.isActive = true
cell.bubbleRightAnchor?.isActive = false
cell.profileImageView.isHidden = false
cell.nameRightAnchor?.isActive = false
cell.nameLeftAnchor?.isActive = true
cell.nameLabel.textColor = .black
cell.nameLabel.text = message.name?.description
}
if let imageUrl = message.imageUrl {
cell.messageImageView.loadImageUsingCacheWithUrlString(imageUrl)
cell.messageImageView.isHidden = false
cell.bubbleView.backgroundColor = .clear
} else {
cell.messageImageView.isHidden = true
}
}
The problem is that I don't think accessing it as a "[index.path]" is the correct way just how I am doing with "messages". How can I access these data structures within the cell setup so I can keep my users information always up-to-date? I am getting errors like "Cannot assign value of type '[CustomerData]' to type 'CustomerData?'" so what is the proper way to access these data structures inside the cell?
The problem is that I don't think accessing it as a "[index.path]" is the correct way just how I am doing with "messages".
This is not true. Passing row or item property of IndexPath as index of element in data source array is correct way how to get certain element.
But, you're using UICollectionView, so you should use item property instead of row even if functionality is the same
UITableView
let item = dataSourceArray[indexPath.row]
UICollectionView
let item = dataSourceArray[indexPath.item]
But you should never pass certain cell as parameter for some other method where you're setting it.
Instead in your collection view cell subclass create method for setting cell's views etc.
class ChatMessageCell: UICollectionViewCell {
...
var message: Message!
...
func setupCell() {
... // here you can work with cell's properites e.g. message, ...
}
}
... and then call it in cellForItemAt
Inside this method you should change things connected with content. "Cosmetic" stuff like changing color of views, etc. you can set inside overridden UICollectionViewCell's method prepareForReuse()
override func prepareForReuse() {
super.prepareForReuse()
...
}

Unable to add dynamic data in expandable tableview iOS swift?

I'm new to iOS development I'm trying to implement expandable table with dynamic data which comes from server. I'm using https://github.com/amratab/ThreeLevelAccordian this expandable table view.
In this library they added statically like below code.
cells.append(TLAHeaderItem(value: "Bathroom" as AnyObject, imageURL: "bathroom_grey_32.png"))
cells.append(TLACell(value: "Shower" as AnyObject))
cells.append(TLASubItem(value: "Shower pores should be cleaned effectively by brushing." as AnyObject))
cells.append(TLACell(value: "Tap" as AnyObject))
cells.append(TLASubItem(value: "Taps must be washed with soap and all the salt removed." as AnyObject))
cells.append(TLACell(value: "Toilet" as AnyObject, imageURL: "toilet_grey_32.png"))
cells.append(TLASubItem(value: "Should be made stains and germs free." as AnyObject))
cells.append(TLAHeaderItem(value: "Bedroom" as AnyObject, imageURL: "bedroom_grey_32.png"))
cells.append(TLACell(value: "Bed" as AnyObject))
cells.append(TLASubItem(value: "Remove all the dust." as AnyObject))
cells.append(TLACell(value: "Dressing" as AnyObject))
cells.append(TLAHeaderItem(value: "Kitchen" as AnyObject, imageURL: "kitchen_grey_32.png"))
cells.append(TLACell(value: "Utensils" as AnyObject))
cells.append(TLASubItem(value: "There are many type of utensils like tongs, rolling pin, pan, non stick pans. Wash them all." as AnyObject))
cells.append(TLACell(value: "Sink" as AnyObject))
cells.append(TLASubItem(value: "Clean the sink" as AnyObject))
in cellforrowindexpath they are using like this.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = self.cells[(indexPath as NSIndexPath).row]
let value = item.value as? String
if let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) {
cell.textLabel?.text = value
let label = cell.textLabel!
cell.imageView?.image = nil
if let headerImage = item.imageURL, let image = UIImage(named: headerImage) {
cell.imageView?.image = image
}
if let accessoryView = accessory(for: indexPath, and: .expand) {
cell.accessoryView = accessoryView
} else {
cell.accessoryType = UITableViewCellAccessoryType.none
cell.accessoryView = nil
}
if let _ = item as? TLAHeaderItem {
if let headerFont = headerCellFont {
cell.textLabel?.font = headerFont
}
if let headerCellBackgroundColor = self.headerCellBackgrondColor {
cell.backgroundColor = headerCellBackgroundColor
}
if let headerCellTextColor = self.headerCellTextColor {
cell.textLabel?.textColor = headerCellTextColor
}
} else if (item as? TLASubItem != nil) {
if isMultiline {
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.numberOfLines = 0
label.sizeToFit()
}
cell.accessoryView = nil
cell.accessoryType = UITableViewCellAccessoryType.none
if let subItemCellBackgrondColor = self.subItemCellBackgrondColor {
cell.backgroundColor = subItemCellBackgrondColor
}
if let subItemCellTextColor = self.subItemCellTextColor {
cell.textLabel?.textColor = subItemCellTextColor
}
if let subItemCellFont = self.subItemCellFont {
cell.textLabel?.font = subItemCellFont
}
} else {
if let itemCellBackgrondColor = self.itemCellBackgrondColor {
cell.backgroundColor = itemCellBackgrondColor
}
if let itemCellTextColor = self.itemCellTextColor {
cell.textLabel?.textColor = itemCellTextColor
}
if let itemCellFont = self.itemCellFont {
cell.textLabel?.font = itemCellFont
}
}
return cell
}
return UITableViewCell()
}
instead of adding statically i want to add dynamically array of data. to the cell.
Example:
cell.textLabel?.text = self.tableViewData[indexPath.row]

File uploading progress issue

I am uploading a single file in a table view cell using AFNetworking.
Uploading is working alright. But when I scroll my cell off view, the progress is gone or some times it displays different progress values like 20% or 50%, and again 30%.
This is my code:
//Tableview Cell configure
var cell : ChattingPhotoCell!
if message.vendorType == .Receiver {
//Receive Image message
cell = tableView.dequeueReusableCell(withIdentifier: "ReceiveChattingPhotoCell") as! ChattingPhotoCell
if cell == nil {
cell = Bundle.main.loadNibNamed("ReceiveChattingPhotoCell", owner: self, options: nil)?[0] as! ChattingPhotoCell
}
cell.reloadDelegate = self
cell.mDelegate = self
cell.accessoryType = cell.isSelected ? .checkmark : .none
cell.conficureImageCell(msg: message,indexPath: indexPath)
} else {
// Send Image Message
cell = tableView.dequeueReusableCell(withIdentifier: "SenderChattingPhotoCell") as! ChattingPhotoCell
if cell == nil {
cell = Bundle.main.loadNibNamed("SenderChattingPhotoCell", owner: self, options: nil)?[0] as! ChattingPhotoCell
}
cell.reloadDelegate = self
cell.mDelegate = self
cell.accessoryType = cell.isSelected ? .checkmark : .none
cell.conficureImageCell(msg: message,indexPath: indexPath)
}
//MyCell code
func conficureImageCell(msg:Message,indexPath:IndexPath) {
self.message = msg
self.indexPath = indexPath
if self.message.vendorType == .Sender {
self.senderCellConfigure()
} else {
self.receiverCellConfigure()
}
}
// sender configure methods
func senderCellConfigure() {
// Send Message
if message.upload == 1 {
self.btnRetry.isHidden = true
}else{
self.btnRetry.isHidden = false
}
if message.is_send == 0 && !self.message.isUploadMedia && message.upload != 1 {
let image = UIImage.init(contentsOfFile: documentDir.path)
if image != nil {
self.uploadImageToServer(ArrImage_Video: NSMutableArray.init(array: [image!]), strMsgType: "3")
}
}
if self.message.isUploadMedia {
self.progressView.isHidden = false
self.btnRetry.isHidden = true
} else {
self.progressView.isHidden = true
}
}
// MARK:- WebserviceCalling // Hiren
func uploadImageToServer(ArrImage_Video:NSMutableArray,strMsgType: String){
self.message.isUploadMedia = true
self.btnRetry.isHidden = true
if self.str_media_url.isBlank {
self.progressView.isHidden = false
let accessToken = Singleton.sharedSingleton.retriveFromUserDefaults(key:Global.kLoggedInUserKey.AccessToken)
print(accessToken!)
let param: NSMutableDictionary = NSMutableDictionary()
param.setValue(fromJID, forKey: "from_user_id")
param.setValue(toJID, forKey: "to_user_id")
param.setValue(strMsgType, forKey: "message_type")
param.setValue("ABC", forKey: "from_user_name")
param.setValue(UIDevice.current.model, forKey: "device_type")
param.setValue("897584acac541d73d5f01f294fe944ddb35b6f67ea894e9ac29b03c7da69ca48", forKey: "device_token")
param.setValue("jpeg", forKey: "file_type")
param.setValue("135", forKey: "message_id")
param.setValue(accessToken, forKey: "access_token")
AFAPIMaster.sharedAPIMaster.PostMediatoServer_chat(params: param, arrMedia: ArrImage_Video, showLoader: false, enableInteraction: true, viewObj: self, onSuccess: {
(DictResponse) in
let dictResponse: NSDictionary = DictResponse as! NSDictionary
let dictData: NSDictionary = dictResponse.object(forKey: "SuccessResponse") as! NSDictionary
let media_url = dictData.object(forKey: "media_url") as? String ?? ""
let media_id = dictData.object(forKey: "id") as? Int ?? 0
let thumb_image = dictData.object(forKey: "thumb_image") as? String ?? ""
print(media_url)
print(thumb_image)
DispatchQueue.main.async {
self.progressView.isHidden = true
let onChatMaster = OnChatMasterTable()
let messageObj = onChatMaster.getMessageFromDB(strMessageID: self.msgID, strFromUId: self.fromJID, strToUId: self.toJID)
messageObj.media_url = media_url
messageObj.thumb_url = thumb_image
messageObj.upload = 1
messageObj.message = self.imageName
messageObj.media_id = media_id
self.str_media_ID = String(media_id)
self.message.media_id = media_id
DBHelper.sharedInstance.queue?.inDatabase() {
db in
DBHelper.sharedInstance.chilaxDB.open()
let strUpdQuery = "UPDATE OnChat_Master SET upload = 1 , media_url = '\(media_url)', thumb_url = '\(thumb_image)' , media_id = \(media_id) where message_id = '\(messageObj.message_id)' AND from_user_id = '\(messageObj.from_user_id)' AND to_user_id = '\(messageObj.to_user_id)'"
DBHelper.sharedInstance.chilaxDB.executeUpdate(strUpdQuery, withArgumentsIn: [])
DBHelper.sharedInstance.chilaxDB.close()
}
//onChatMaster.updateMessageInDB(messsageObj: messageObj)
self.sendMediaDataToSender(media_url: media_url, thumb_image: thumb_image,strMediaId:self.str_media_ID)
self.message.isUploadMedia = false
}
}, displayProgress: {
(progress) in
DispatchQueue.main.async {
let progressTask : Float = Float((progress as! Progress).fractionCompleted)
print(progressTask)
self.progressView.setProgress(progressTask, animated: true)
}
}, onFailure: {
self.progressView.setProgress(0.0, animated: true)
self.progressView.isHidden = true
self.btnRetry.isHidden = false
self.message.isUploadMedia = false
})
} else {
self.sendMediaDataToSender(media_url: str_media_url, thumb_image: str_thumb_url, strMediaId: str_media_ID)
}
}
I reuse cell using table view deque methods. Any wrong in this code.

how to enable the radio button depending on the data coming from web services?

here i had implemented a custom design like the image shown here i need to active the radio button depending on my web services data. In web services one key value pair i was receiving 0 & 1 only in that if it is 1 then i need to make active the radio button any help how to implement ?
here is the code for my radio button
#IBAction func selectRadioButton(_ sender: KGRadioButton) {
let chekIndex = self.checkIsRadioSelect.index(of: sender.tag)
let checkIndex = self.checkIsButtonEnable.index(of: sender.tag)
if sender.isSelected {
} 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()
}
}
}
here is the code for table view
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! addressTableViewCell
tableDetails.isHidden = false
myActivityIndicator.stopAnimating()
let arr = detailsArray[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)
let defaultaddress : Int = arr["default"] as! Int
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){
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
In your cellForRowAtIndexPath method update code like below
My suggestion is Don't set indexPath.row as tag while reusing tableView cells it won't give you better result.Make some unique id as tag. or do some math calculation something adding/multiplying with numbers.
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! addressTableViewCell
tableDetails.isHidden = false
myActivityIndicator.stopAnimating()
let arr = detailsArray[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
cell.radioButton.isSelected = false
if let isDefault = arr["default"] as? Bool { // i think it won't be Integer it will be Bool,please debug & check it
cell.radioButton.isSelected = isDefault
cell.editButton.isHidden = false
cell.deleteButton.isHidden = false
}
let checkIndex = self.checkIsRadioSelect.index(of: indexPath.row)
if(checkIndex != nil){
cell.radioButton.isSelected = true
cell.editButton.isHidden = false
cell.deleteButton.isHidden = false
}
Change the below line of code.
let checkIndex = self.checkIsRadioSelect.index(of: indexPath.row) //delete this line
let checkIndex = arr["default"] as! Int //use radio button key.
#IBAction func selectRadioButton(_ sender: KGRadioButton) {
let arr = detailsArray[sender.tag]
if sender.isSelected {
arr["default"] = #"0"
} else{
arr["default"] = #"1"
}
self.tableDetails.reloadData()
}

How to filter an array of JSON objects to be used in a table view?

I'm getting JSON data from an API and parsing that data in objects, which are then simply stored in an array of objects. The objects themselves contain data about articles from a newspaper. However, I need to filter that data. Some of the objects I'm getting from my JSON actually have no article content because they are pictures and not articles (i.e. some of the "nodes" from the API's JSON have content that I don't want to see in my table view).
In my JSON-parsing function, I've tried to make it so that the parsed object will only get added to the array of parsed objects if the character count of the "articleContent" variable is above 40. Here is what it looked like.
if issueElement.articleContent.characters.count > 40 {
self.currentIssueObjects.addObject(issueElement)
}
However, this simply does not work. I get the typical "unexpectedly found nil while unwrapping an Optional value" error message (I don't get a specific line for the error). How can I make this work ? I'm essentially trying to prevent the array from having objects with empty articleContent, because then that screws up my table view (empty cells, duplicates, etc...).
Here is my cellForRowAtIndexPath code, and my JSON-parsing code:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell {
let row = indexPath.row
guard let cell = tableView.dequeueReusableCellWithIdentifier(CurrentIssueArticlesTableCellIdentifier, forIndexPath: indexPath) as? CurrentIssueArticlesTableViewCell else {
print ("error: currentIssueTableView cell is not of class CurrentIssueArticlesTableViewCell, we will use EditorialsTableViewCell instead")
return tableView.dequeueReusableCellWithIdentifier(CurrentIssueArticlesTableCellIdentifier, forIndexPath: indexPath) as! EditorialsTableViewCell
}
let currentIssueObject = currentIssueObjects.objectAtIndex(indexPath.row) as! IssueElement
let title = currentIssueObject.title ?? ""
let timeStampDateObject = NSDate(timeIntervalSince1970: NSTimeInterval(currentIssueObject.timeStamp))
let timeStampDateString = dateFormatter.stringFromDate(timeStampDateObject) ?? "Date unknown"
if let author = currentIssueObject.author {
cell.currentIssueArticlesAuthorLabel!.font = UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
cell.currentIssueArticlesAuthorLabel!.text = author
}
let issueNumber = currentIssueObject.issueNumber ?? ""
let volumeNumber = currentIssueObject.volumeNumber ?? ""
let articleContent = currentIssueObject.articleContent ?? ""
let nodeID = currentIssueObject.nodeID ?? 0
cell.currentIssueArticlesHeadlineLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cell.currentIssueArticlesHeadlineLabel.text = title
cell.currentIssueArticlesPublishDateLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
cell.currentIssueArticlesPublishDateLabel.text = timeStampDateString
if row == 0 {
cell.userInteractionEnabled = false
let imageURL = (currentIssueObjects.objectAtIndex(row) as! IssueElement).imageURL
cell.currentIssueArticlesHeadlineLabel.textColor = UIColor.clearColor()
cell.currentIssueArticlesAuthorLabel.textColor = UIColor.clearColor()
cell.currentIssueArticlesPublishDateLabel.textColor = UIColor.clearColor()
cell.request?.cancel()
if let image = self.imageCache.objectForKey(imageURL!) as? UIImage {
cell.currentIssueArticlesBackgroundImageView.image = image
} else {
cell.currentIssueArticlesBackgroundImageView.image = UIImage(named: "reveal Image")
cell.request = Alamofire.request(.GET, imageURL!).responseImage() { response in
if response.result.error == nil && response.result.value != nil {
self.imageCache.setObject(response.result.value!, forKey: response.request!.URLString)
cell.currentIssueArticlesBackgroundImageView.image = response.result.value
} else {
}
}
}
cell.currentIssueArticlesBackgroundImageView.hidden = false
}
else {
cell.currentIssueArticlesBackgroundImageView.hidden = true
}
return cell
}
JSON-parsing code:
func populateCurrentIssue() {
if populatingCurrentIssue {
return
}
populatingCurrentIssue = true
self.cellLoadingIndicator.backgroundColor = goldenWordsYellow
self.cellLoadingIndicator.startAnimating()
Alamofire.request(GWNetworking.Router.Issue).responseJSON() { response in
if let JSON = response.result.value {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
var nodeIDArray : [Int]
if (JSON .isKindOfClass(NSDictionary)) {
for node in JSON as! Dictionary<String, AnyObject> {
let nodeIDValue = node.0
var lastItem : Int = 0
self.nodeIDArray.addObject(nodeIDValue)
if let issueElement : IssueElement = IssueElement(title: "Could not retrieve title", nodeID: 0, timeStamp: 0, imageURL: "init", author: "Author not found", issueNumber: "Issue # error", volumeNumber: "Volume # error", articleContent: "Could not retrieve article content", coverImageInteger: "init", coverImage: UIImage()) {
issueElement.title = node.1["title"] as! String
issueElement.nodeID = Int(nodeIDValue)!
let timeStampString = node.1["revision_timestamp"] as! String
issueElement.timeStamp = Int(timeStampString)!
issueElement.imageURL = String(node.1["image_url"])
if let author = node.1["author"] as? String {
issueElement.author = author
}
if let issueNumber = node.1["issue_int"] as? String {
issueElement.issueNumber = issueNumber
}
if let volumeNumber = node.1["volume_int"] as? String {
issueElement.volumeNumber = volumeNumber
}
if let articleContent = node.1["html_content"] as? String {
issueElement.articleContent = articleContent
}
issueElement.coverImageInteger = String(node.1["cover_image"]) // addition specific to the Current Issue View Controller
lastItem = self.currentIssueObjects.count
print(issueElement.nodeID)
if issueElement.articleContent.characters.count > 40 {
self.currentIssueObjects.addObject(issueElement)
print(issueElement.nodeID)
}
// Sorting with decreasing timestamp from top to bottom.
let timestampSortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
self.currentIssueObjects.sortUsingDescriptors([timestampSortDescriptor])
// Placing the object with coverImage
let coverImageSortDescriptor = NSSortDescriptor(key: "coverImageInteger", ascending: false)
self.currentIssueObjects.sortUsingDescriptors([coverImageSortDescriptor])
let indexPaths = (lastItem..<self.currentIssueObjects.count).map {
NSIndexPath(forItem: $0, inSection: 0) }
}
}
}
dispatch_async(dispatch_get_main_queue()) {
self.currentIssueTableView.reloadData()
self.cellLoadingIndicator.stopAnimating()
self.cellLoadingIndicator.hidesWhenStopped = true
}
}
}
self.populatingCurrentIssue = false
}
}

Resources