I have a SWRevealViewController Application. I have been unsuccessfully trying to set the background color with self.view.backgroundColor. The specific example i show below is a UIViewController that contains a tableView with a empty UIView() footer to stop the tableView when it is finished. I am trying to set the backgroundColor to fill the remaining space. My code below.
import UIKit
class NewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSXMLParserDelegate {
#IBOutlet weak var tables: UITableView!
var parser: NSXMLParser = NSXMLParser()
var info: [newsarticle] = []
var postTitle: String = String()
var postDesc: String = String()
var eName: String = String()
var index: Int = Int()
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
let navicon = UIButton(type: UIButtonType.System)
navicon.setImage(defaultMenuImage(), forState: UIControlState.Normal)
navicon.frame = CGRectMake(0, 0, 30, 30)
let menu = UIBarButtonItem(customView: navicon)
self.navigationItem.leftBarButtonItem = menu
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
navicon.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), forControlEvents: .TouchUpInside)
let url:NSURL = NSURL(string: "http://brrsd.k12.nj.us/rss/News.xml")!
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(NewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
tables.separatorColor = UIColor.init(red: 217/255, green: 180/255, blue: 74/255, alpha: 1)
tables.addSubview(refreshControl)
//background.frame = self.view.frame
tables.tableFooterView = UIView()
self.view.backgroundColor = UIColor.init(red: 241/255, green: 241/255, blue: 242/255, alpha: 1)self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
func refresh(sender: AnyObject)
{
info = [newsarticle]()
let url:NSURL = NSURL(string: "http://brrsd.k12.nj.us/rss/News.xml")!
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
tables.reloadData()
refreshControl.endRefreshing()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60;
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI namespaceURI: String?, qualifiedName qualifiedName: String?, attributes attributeDict: [String : String])
{
eName = elementName
if elementName == "item" {
postTitle = String()
postDesc = String()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return info.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell
if let reusedCell = tableView.dequeueReusableCellWithIdentifier("Cell") {
cell = reusedCell
} else {
cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
}
let news: newsarticle = info[indexPath.row]
if let label = cell.textLabel {
label.text = news.title
}
cell.backgroundColor = UIColor.init(red: 241/255, green: 241/255, blue: 242/255, alpha: 1)
cell.textLabel!.font = UIFont(name:"Bodoni 72", size: 16)
cell.textLabel!.textColor = UIColor.init(red: 25/255, green: 149/255, blue: 173/255, alpha: 1)
return cell }
func parser(parser: NSXMLParser, foundCharacters string: String) {
let data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if (!data.isEmpty) {
if eName == "title" {
postTitle += data
} else if eName == "description" {
postDesc += data
}
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
let newsart: newsarticle = newsarticle()
newsart.title = postTitle
newsart.description = postDesc
info.append(newsart)
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
index = indexPath.row
tables.deselectRowAtIndexPath(indexPath, animated:true)
performSegueWithIdentifier("NewsTransfer", sender:self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Destination: FullNews = segue.destinationViewController as! FullNews
Destination.info = info[index]
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
In your viewDidLoad method, you have:
tables.tableFooterView = UIView()
Try this instead:
tables.tableFooterView = UIView(frame: CGRectZero)
Also, for the next line (the background color), try this:
self.view.window!.backgroundColor = UIColor(red: 241/255, green: 241/255, blue: 242/255, alpha: 1.0)
Related
I am creating an Event App, wherein the list of participants fetch from API are listed in an UITableView. When the user tapped the checkInOutbutton its either, it will check in and register for the event or check out after the event. In every after the user checkin or checkout from the event, the user should pull to refresh to update the data inside the table. I used the codes below to update the data.
var refresher: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
refresher.addTarget(self, action: #selector(ParticipantsViewController.refresh), for: UIControlEvents.valueChanged)
ParticipantTableView.addSubview(refresher)
}
//MARK: FUNCTIONS
#objc func refresh() {
refresher.endRefreshing()
getParticipants()
ParticipantTableView.reloadData()
_ = SCLAlertView(appearance: Appearance).showSuccess("Success", subTitle: "Participants Updated!")
}
I successfully updated the table once I used pull to refresh. The issue is, when I tapped the back button going to my dashboard and tapped the button going back to the VC of my UItableview which is participantViewController, the data is not updated. It goes back to its original data. How can I retain the updated data even if I tapped the back button and goes back to theparticipantsorregistered participants` VC?. Hope you can help me.
original data, gray bgcolor and NOT REGISTERED label(checkin and checkout button is inside the folding cell
.
data once the user tapped checkin button, the background colour turned to green and label is REGISTERED
Dashboard when back button is tapped
Back button when tapped
#IBAction func backbutton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
ParticipantViewController
import UIKit
import FoldingCell
import SCLAlertView
import AASquaresLoading
class ParticipantsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var ParticipantTableView: UITableView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var countLabel: UILabel!
#IBOutlet weak var notifImageView: UIImageView!
var refresher: UIRefreshControl!
var validPincode: String!
var titleString: String!
var participants: [Attendee]!
var filteredParticipants = [Attendee]()
let kCloseCellHeight: CGFloat = 122
let kOpenCellHeight: CGFloat = 475
var cellHeights = [CGFloat]()
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
createCellHeightsArray()
configureSearchBar()
configureAALoading()
countNotif()
titleLabel.text = self.titleString
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
refresher.addTarget(self, action: #selector(ParticipantsViewController.refresh), for: UIControlEvents.valueChanged)
ParticipantTableView.addSubview(refresher)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
self.ParticipantTableView.reloadData()
}
#IBAction func backbutton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
//MARK: FUNCTIONS
#objc func refresh() {
refresher.endRefreshing()
getParticipants()
ParticipantTableView.reloadData()
_ = SCLAlertView(appearance: Appearance).showSuccess("Success", subTitle: "Participants Updated!")
}
func configureAALoading() {
self.view.squareLoading.color = UIColor(red: 80/255.0, green: 187/255.0, blue: 113/255.0, alpha: 1.0)
self.view.squareLoading.backgroundColor = UIColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.7)
}
func getParticipants() {
var participantType: ParticipantType!
if self.titleString == "PARTICIPANTS" {
participantType = .all
}else {
participantType = .active
}
self.view.squareLoading.start(0.0)
let api = APIService()
api.getParticipants(enteredPincode: validPincode, participantType: participantType, successBlock: { (attendees) in
self.participants = attendees
self.view.squareLoading.stop(0.0)
if self.searchController.isActive && self.searchController.searchBar.text != "" {
self.filterContentForSearchText(searchText: self.searchController.searchBar.text!)
}else {
self.ParticipantTableView.reloadData()
}
}) { (error) in
// Hide loading view
self.view.squareLoading.stop(0.0)
_ = SCLAlertView(appearance: Appearance).showError("Network Error", subTitle: "\(error)")
}
}
func countNotif(){
if participants.count == 0 {
countLabel.isHidden = true
notifImageView.isHidden = true
}else {
countLabel.text = "\(participants.count)"
notifImageView.image = #imageLiteral(resourceName: "participant_notif")
}
}
func createCellHeightsArray() {
cellHeights.removeAll()
if searchController.isActive && searchController.searchBar.text != "" {
for _ in 0...filteredParticipants.count {
cellHeights.append(kCloseCellHeight)
}
}else {
for _ in 0...participants.count {
cellHeights.append(kCloseCellHeight)
}
}
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredParticipants = participants.filter { participants in
return participants.displayName.lowercased().contains(searchText.lowercased()) || (participants.department.lowercased().contains(searchText.lowercased()))
// || (participants.employeeNumber?.contains(searchText))! ||
}
createCellHeightsArray()
ParticipantTableView.reloadData()
}
func configureSearchBar() {
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
searchController.searchBar.textColor = UIColor.white
searchController.searchBar.placeholder = "Search by name, department, and employee number"
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.barTintColor = UIColor(red: 26/255.0, green: 99/255, blue: 42/255, alpha: 1.0)
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.backgroundColor = UIColor(red: 26/255.0, green: 99/255, blue: 42/255, alpha: 1.0)
searchController.searchBar.isTranslucent = false
self.ParticipantTableView.tableHeaderView = searchController.searchBar
}
// MARK: TABLE VIEW DATA SOURCE
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filteredParticipants.count
}
//print(participants.count)
return (participants.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FoldingCell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard case let cell as ParticipantCell = cell else {
return
}
cell.backgroundColor = UIColor.clear
if searchController.isActive && searchController.searchBar.text != "" {
cell.participant = filteredParticipants[indexPath.row]
}else {
cell.participant = participants[indexPath.row]
}
if cellHeights[(indexPath as NSIndexPath).row] == kCloseCellHeight {
cell.unfold(false, animated: false, completion: nil)
} else {
cell.unfold(true, animated: false, completion: nil)
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[(indexPath as NSIndexPath).row]
}
// MARK: TABLE VIEW DELEGATE
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! FoldingCell
if cell.isAnimating() {
return
}
var duration = 0.0
if cellHeights[(indexPath as NSIndexPath).row] == kCloseCellHeight { // open cell
cellHeights[(indexPath as NSIndexPath).row] = kOpenCellHeight
cell.unfold(true, animated: true, completion: nil)
duration = 0.3
} else {// close cell
cellHeights[(indexPath as NSIndexPath).row] = kCloseCellHeight
cell.unfold(false, animated: true, completion: nil)
duration = 0.5
}
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: { () -> Void in
tableView.beginUpdates()
tableView.endUpdates()
}, completion: nil)
}
}
extension ParticipantsViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
}
extension UISearchBar {
var textColor: UIColor? {
get {
if let textField = self.value(forKey: "searchField") as? UITextField {
return textField.textColor
}else {
return nil
}
}
set (newValue) {
if let textField = self.value(forKey: "searchField") as? UITextField {
textField.textColor = newValue
textField.font = UIFont(name: "HelveticaNeue", size: 20.0)
}
}
}
}
Your explanation of the problem is kind of confusing to me but I think I understand what you're saying. My interpretation: You present a the view controller for a tableView and refresh the table view with some new data. Then when you dismiss the view controller and go back to it, the new data is gone and you just see the old data.
Well if that's your problem, then the solution is pretty simple. When you return to the view controller, you're probably just creating a completely new viewController and presenting it... which isn't gonna have the new data that was fetched from the network.
In that case you would have to store that original viewController instance in a variable and present THAT, instead of creating an entirely new one.
Edit:
somewhere in your code for the dashboard, you probably have this line
self.present(ParticipantsViewController(), animated: false)
...or some variant of that. Instead of this, do something along the lines of...
class DashboardViewController: UIViewController{
var participantsViewController = ParticipantsViewController()
func responseToSomeUserAction(){
self.present(self.participantsViewController, animated: true)
}
}
In the code above, the same viewController instance will be presented every time the user wants to display the table view, therefore all the data will still be there.
I have a UITableView with data, that parsed from url.
UITableView will load more data, when scrolled right to the bottom (or got some more space to scroll, but close to the end - did both, same results)
When more data is loaded - i simple append it to array of my class, that contains data for TableView and then list scrolls back more than half of list (e.g. got 40 items, loading 10 more -> scrolling back to 20-25).
Calling TableView.reloadData() after append is complete.
Is there some mistakes in plan of doing it?
I can share code, but it's pretty common.
class TabAllTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, XMLParserDelegate {
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var BlogAllTableView: UITableView!
var loadMoreStatus = false
var maxPage = 1.0
var currentPageLoad = 1.0
var blogList: [DetailAndRenderBlogObject] = []
var eName: String = String()
var category = String()
var full_text = String()
var short_text = String()
var blog_title = String()
var avatar = String()
var full_name = String()
var url = String()
var created_at = String()
private let CATEGORY = ConfigData.CATEGORY_ALL
let cellIdentifier = "BlogTableViewCell"
override func viewDidLoad() {
super.viewDidLoad()
setupNavMenuButtons()
self.BlogAllTableView.insertSubview(refreshControl, at: 0)
self.BlogAllTableView.tableFooterView?.isHidden = true
downloadBlogData(1, true, true)
BlogAllTableView.delegate = self
BlogAllTableView.dataSource = self
}
var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:
#selector(TabAllTableViewController.handleRefresh(_:)),
for: UIControlEvents.valueChanged)
refreshControl.tintColor = Colors.ColorLoadingIndicator
return refreshControl
}()
#objc func handleRefresh(_ refreshControl: UIRefreshControl) {
downloadBlogData(1, true, false)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
let deltaOffset = maximumOffset - currentOffset
if deltaOffset <= 0 && currentPageLoad < maxPage {
loadMore()
}
}
func loadMore() {
if ( !loadMoreStatus ) {
self.loadMoreStatus = true
self.activityIndicator.startAnimating()
self.BlogAllTableView.tableFooterView?.isHidden = false
downloadBlogData(currentPageLoad, false, false)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.sideMenuController?.isLeftViewEnabled = true
AppDelegate.tabBarReference.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.navigationBar.topItem?.title = "all".localized()
}
private func setupNavMenuButtons() {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(handleMenuRefresh))
let image = UIImage(named:"menu_ham.png")
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView.image = image
let imageHeight = navigationController?.navigationBar.frame.size.height
let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: imageHeight!, height: imageHeight!))
wrapperView.addSubview(imageView)
imageView.center = CGPoint(x: imageView.frame.size.width / 2, y: wrapperView.frame.size.height / 2)
let tap = UITapGestureRecognizer(target: self, action: #selector(TabAllTableViewController.menuButtonClick))
wrapperView.addGestureRecognizer(tap)
let btnHamburgerMenu: UIBarButtonItem = UIBarButtonItem(customView: wrapperView)
navigationItem.setLeftBarButton(btnHamburgerMenu, animated: false)
}
#objc private func menuButtonClick()
{
self.sideMenuController?.showLeftViewAnimated()
}
#objc private func handleMenuRefresh() {
downloadBlogData(1, true, true)
}
func numberOfSections(in tableView: UITableView) -> Int {
return blogList.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if (section != 0) {
return 12
} else {
return CGFloat.leastNonzeroMagnitude
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.0)
return view
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(ConfigData.CELL_HEIGHT)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? BlogTableViewCell else {
fatalError("The dequeued cell is not an instance of BlogTableViewCell.")
}
cell.layer.cornerRadius = 10
let blogItem = blogList[indexPath.section]
cell.avatarBackground.contentMode = .scaleAspectFill
cell.avatarBackground.layer.cornerRadius = cell.avatarBackground.frame.size.width / 2;
cell.avatarBackground.clipsToBounds = true;
if let authorImgUrl = URL(string: blogItem.authorImg) {
cell.authorRoundImage.contentMode = .scaleAspectFill
cell.authorRoundImage.layer.cornerRadius = cell.authorRoundImage.frame.size.width / 2;
cell.authorRoundImage.clipsToBounds = true;
//Helper.downloadImage(url: authorImgUrl, imageview: cell.authorRoundImage)
cell.authorRoundImage.sd_setImage(with: authorImgUrl)
}
if let headerImageUrl = URL(string: blogItem.image) {
cell.bigImage.contentMode = .scaleToFill
//Helper.downloadImage(url: headerImageUrl, imageview: cell.bigImage)
cell.bigImage.sd_setImage(with: headerImageUrl)
}
cell.authorLabel.text = blogItem.author
cell.dateLabel.text = blogItem.date
cell.title.text = blogItem.title
cell.titleDescription.text = blogItem.shortDescription
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let secondViewController = self.storyboard!.instantiateViewController(withIdentifier: "ShowArticleViewController") as! ShowArticleViewController
secondViewController.blogItem = blogList[indexPath.section]
self.navigationController!.pushViewController(secondViewController, animated: true)
}
private func downloadBlogData(_ page : Double, _ refresh : Bool, _ showOverlay : Bool) {
// print(InAppProperties.sharedInstance.getDefaulLang())
if showOverlay {
LoadingOverlay.shared.showOverlay(view: self.view)
}
let req = NSMutableURLRequest(url: NSURL(string: Helper.getBlogUrl(CATEGORY, Int(page)))! as URL)
req.httpMethod = "GET"
req.httpBody = "key=\"value\"".data(using: String.Encoding.utf8) //This isn't for GET requests, but for POST requests so you would
URLSession.shared.dataTask(with: req as URLRequest) { data, response, error in
if error != nil {
//Your HTTP request failed.
print(error?.localizedDescription)
} else {
//Your HTTP request succeeded
if refresh {
self.currentPageLoad = 1
} else {
self.currentPageLoad += 1
}
let stringData = String(data: data!, encoding: String.Encoding.utf8)!
//print(stringData)
let xml = SWXMLHash.parse(stringData)
if page == 1 {
self.blogList = [DetailAndRenderBlogObject]()
}
for elem in xml["response"]["provider"].all {
let itemList = elem["item"]
for article in itemList.all {
let blogItem = DetailAndRenderBlogObject()
blogItem.articleUrl = article["url"].element!.text
blogItem.author = article["full_name"].element!.text
blogItem.authorImg = article["avatar"].element!.text
blogItem.text = article["full_text"].element!.text
blogItem.shortDescription = article["short_text"].element!.text
blogItem.title = article["title"].element!.text
blogItem.categoryUrl = article["category"].element!.text
blogItem.image = self.repairLink(article["thumbnail"].element!.text)
blogItem.date = self.formatDate(article["created_at"].element!.text)
if (blogItem.categoryUrl.lowercased().range(of:"video") == nil &&
blogItem.title.lowercased().range(of: "видео") == nil) {
self.blogList.append(blogItem)
}
}
if let totalItemsCount = xml["response"]["pagination"]["totalCount"].element?.text {
self.maxPage = (Double(totalItemsCount)! / 10).rounded(.up)
}
}
DispatchQueue.main.async {
self.BlogAllTableView.reloadData()
self.refreshControl.endRefreshing()
self.loadMoreStatus = false
self.activityIndicator.stopAnimating()
self.BlogAllTableView.tableFooterView?.isHidden = true
if showOverlay {
LoadingOverlay.shared.hideOverlayView()
}
if (page == 1) {
let indexPath = NSIndexPath(row: 0, section: 0)
self.BlogAllTableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
}
}
}
}.resume()
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
eName = elementName
if elementName == "item" {
category = String()
full_text = String()
short_text = String()
blog_title = String()
avatar = String()
full_name = String()
url = String()
created_at = String()
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
let blogListItem = DetailAndRenderBlogObject()
blogListItem.categoryUrl = category
blogListItem.text = full_text
blogListItem.shortDescription = short_text
blogListItem.title = blog_title
blogListItem.authorImg = avatar
blogListItem.author = full_name
blogListItem.articleUrl = url
blogListItem.date = created_at
print("WRITING DATA")
blogList.append(blogListItem)
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
//print("ENAME: " + eName)
switch eName {
case "category":
print("writing category: " + string)
category = string;
case "full_text":
full_text = string;
case "short_text":
short_text = string;
case "title":
title = string;
case "thumbnail":
avatar = string;
case "avatar":
avatar = string;
case "full_name":
full_name = string;
case "url":
url = string;
case "created_at":
created_at = string;
default:
()
}
}
func parserDidEndDocument(_ parser: XMLParser) {
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func repairLink(_ link : String) -> String { //sometimes links looks like https://asdasd.comhttps://asdasd.com/...
let newLink = link.suffix(from: link.index(link.startIndex, offsetBy: 1))
if let range = newLink.range(of: "http") {
let substring = newLink[range.lowerBound...]
return String(substring)
}
return link
}
func formatDate(_ date : String) -> String { //date String "2018-01-22 08:59:43"
if let dividerIndex = date.index(of: " ") {
return String(date[..<dividerIndex])
}
return date
}
}
Reloading the entire table is quite an intensive operation. The better way might be to use the tableView.insertRows(at:with:) method. An example would be something like -
func didFinishLoadingData(newBlogs: [DetailAndRenderBlogObject]) {
tableView.beginUpdates()
var indexPaths: [IndexPath] = []
for row in (blogList.count..<(blogList.count + newBlogs.count)) {
indexPaths.append(IndexPath(row: row, section: 0))
}
blogList.append(contentsOf: newBlogs)
tableView.insertRows(at: indexPaths, with: .fade)
tableView.endUpdates()
}
I had the same issue and found another solution, after long time search.
It seems that whenever you call the endRefreshing() function of an UIRefreshControl that is attached to a UITableView scrollview, it stops the decelerating process of the scroll view.
So, if your code, that fetches the next page, is calling endRefreshing() function (with no reason at all) and the user started the scrolling and lifted his/her finger from the device's screen (scrollview is decelerating) this will have as a result to stop the scrolling.
The solution is simple, replace this line in your code:
self.refreshControl.endRefreshing()
with these lines:
if self.refreshControl.isRefreshing {
self.refreshControl.endRefreshing()
}
I even created a handy extension that does this check for me, to call it whenever I need it:
extension UIRefreshControl {
func endIfRefreshing() {
if isRefreshing { endRefreshing() }
}
}
I´m having some trouble implementing a SearchBar to my TableView with IndexPath.row data
I cannot figure out what to do with this error message:
Cannot convert value of type (String) -> Bool to expected argument type (postStruct) -> Bool
I get this error message in the func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
Here is my code
import UIKit
import Firebase
import FirebaseDatabase
struct postStruct {
let username : String!
let school : String!
}
class TableViewProfileController: UITableViewController, UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
var posts:[postStruct] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Find friends"
searchBar.delegate = self
tableView.dataSource = self
//Hide backButton in Navigationbar
self.navigationItem.setHidesBackButton(true, animated: false)
// SearchController
searchBar.sizeToFit()
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search here..."
searchBar.setShowsCancelButton(false, animated: true)
searchBar.keyboardAppearance = .default
searchBar.tintColor = UIColor(red: 38.0/255.0, green: 68.0/255.0, blue: 102.0/255.0, alpha: 1.0)
self.definesPresentationContext = true
self.tableView.reloadData()
// TableView Cell Content
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let username = snapshotValue!["Username"] as! String
let school = snapshotValue!["School"] as! String
self.posts.insert(postStruct(username: username, school: school) , at: 0)
self.tableView.reloadData()
})
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
posts = searchText.isEmpty ? posts : posts.filter({(dataString: String) -> Bool in
return dataString.range(of: searchText, options: .caseInsensitive) != nil
})
tableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 2.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].username
label1.font = UIFont(name: "Arial Rounded MT Bold", size: 16)
label1.textColor = UIColor.black
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].school
label2.font = UIFont(name: "Arial", size: 11)
label2.textColor = UIColor(red: 102.0/255.0, green: 102.0/255.0, blue: 102.0/255.0, alpha: 1.0)
cell?.imageView?.image = UIImage(named: "Userlogo")
return cell!
}
//Preparing Segue to show username in FindUserViewController
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "findSegue", sender: self.posts[indexPath.row].username)
}
//Segue to show username in FindUserViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier! == "findSegue" {
let guest = segue.destination as! FindUserViewController
guest.pickedUser = sender as! String
let backItem = UIBarButtonItem()
backItem.title = "Back"
navigationItem.backBarButtonItem = backItem
}
}
}
You are applying the filter function to an postStruct array, so the syntax is at least
posts.filter({ (post: postStruct) -> Bool in ... })
or shorter
posts.filter { post in ... }
You could search for
posts = searchText.isEmpty ? posts : posts.filter { post in
return post.username.range(of: searchText, options: .caseInsensitive) != nil
}
Side-note:
Please, please do not - never do – declare implicit unwrapped optional members in a struct.
Either they are indeed optional then declare them as String? or they are non-optional then cut the exclamation mark.
I have to retrieve images from Parse, and I am working on this code:
class ViewControllerHome: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var MessageTable: UITableView!
let color = UIColor(red: 0.0/255.0, green: 105.0/255.0, blue: 92.0/255.0, alpha: 1)
let colore = UIColor.whiteColor()
let coloree = UIColor(red: 33.0/255.0, green: 33.0/255.0, blue: 33.0/255.0, alpha: 1)
var Username = [String]()
var Image = [PFFile]()
var Likes = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
var refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: Selector("refreshPulled"), forControlEvents: UIControlEvents.ValueChanged)
loadData()
self.MessageTable.reloadData()
self.navigationController?.navigationBar.barTintColor = color
self.navigationController?.navigationBar.tintColor = colore
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: colore]
UITabBar.appearance().barTintColor = coloree
UITabBar.appearance().tintColor = colore
UITabBar.appearance().translucent = false
self.MessageTable.delegate = self
self.MessageTable.dataSource = self
func refreshPulled() {
loadData()
self.MessageTable.reloadData()
refreshControl.endRefreshing()
}
}
func loadData() {
let query = PFQuery(className: "Messages")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(posts: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
if let posts = posts as [PFObject]? {
for post in posts{
self.Image.append(post["Post"] as! PFFile)
self.Username.append(post["Name"] as! String)
self.Likes.append(post["Vote"] as! Int)
}
}
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.MessageTable.dequeueReusableCellWithIdentifier("cell")! as! TableViewCellHome
var imagesToLoad = self.Image[indexPath.row] as PFFile
var imagesUser = self.Username[indexPath.row] as String
var imageLikes = self.Likes[indexPath.row] as Int
//This line gives me an error: call can throw, but is not marked with 'try' and the error is not handled
var imagesdata = imagesToLoad.getData()
var finalizedImage = UIImage(data: imagesdata)
cell.PostImage.image = finalizedImage
cell.UsernameLabel.text = imagesUser
cell.LikesLabel.text = "\(imageLikes)"
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Username.count
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
This code should get and display Image, string and Int Value from parse's backend. The problem is that nothing is displayed. How can I change the code so that this will display correctly? There is also an error at the line:
var imagesdata = imagesToLoad.getData()
This line tells me
call can throw, but is not marked with 'try' and the error is not handled
Thanks in advance to anyone that can help me solve this problem.
I'm working on an app that let's users post, like and comment, so as part of my comment implementation, I'm trying to display the user's post, so you are able to comment on it. I am using a UITableView that is the main timeline and it displays all of the posts users have made, so what I'm trying to do is that when a user clicks on a cell, it displays the post of that cell so you are able to comment on it, but I'm having trouble displaying it.
This is the code that I have for that implementation so far, so what am I missing?
Is there anything else that I can do to be able to display the selected post in a viewController after the user clicks on the cell?
import UIKit
import Parse
class DetailViewContoller: UIViewController, UITableViewDelegate, UITextViewDelegate {
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var postLabel: UILabel!
#IBOutlet weak var commentTableView: UITableView!
var post: PFObject?
var commentView: UITextView?
var footerView: UIView?
var contentHeight: CGFloat = 0
var comments: [String]?
let FOOTERHEIGHT : CGFloat = 50;
override func viewDidLoad() {
super.viewDidLoad()
commentTableView.delegate = self
/* Setup the keyboard notifications */
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
if(post?.objectForKey("comments") != nil) {
comments = post?.objectForKey("comments") as? [String]
}
println(post)
println(post?.objectForKey("content"))
self.postLabel.text = post?.objectForKey("content") as? String
}
func keyBoardWillShow(notification: NSNotification) {
var info:NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
var keyboardHeight:CGFloat = keyboardSize.height - 40
var animationDuration:CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as! CGFloat
var contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
self.commentTableView.contentInset = contentInsets
self.commentTableView.scrollIndicatorInsets = contentInsets
}
func keyBoardWillHide(notification: NSNotification) {
self.commentTableView.contentInset = UIEdgeInsetsZero
self.commentTableView.scrollIndicatorInsets = UIEdgeInsetsZero
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = comments?.count {
return count
}
return 0
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = commentTableView.dequeueReusableCellWithIdentifier("commentCell", forIndexPath: indexPath) as! CommentTableViewCell
cell.commentLabel?.text = comments![indexPath.row]
return cell
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if self.footerView != nil {
return self.footerView!.bounds.height
}
return FOOTERHEIGHT
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
footerView = UIView(frame: CGRect(x: 0, y: 0, width: commentTableView.bounds.width, height: FOOTERHEIGHT))
footerView?.backgroundColor = UIColor(red: 243.0/255, green: 243.0/255, blue: 243.0/255, alpha: 1)
commentView = UITextView(frame: CGRect(x: 10, y: 5, width: commentTableView.bounds.width - 80 , height: 40))
commentView?.backgroundColor = UIColor.whiteColor()
commentView?.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
commentView?.layer.cornerRadius = 2
commentView?.scrollsToTop = false
footerView?.addSubview(commentView!)
let button = UIButton(frame: CGRect(x: commentTableView.bounds.width - 65, y: 10, width: 60 , height: 30))
button.setTitle("Reply", forState: UIControlState.Normal)
button.backgroundColor = UIColor(red: 0/0.0, green: 179/255.0, blue: 204/255.0, alpha: 100.0/100.0)
button.layer.cornerRadius = 5
button.addTarget(self, action: "reply", forControlEvents: UIControlEvents.TouchUpInside)
footerView?.addSubview(button)
commentView?.delegate = self
return footerView
}
//Hide keyboard after touching background
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
//remaining characters
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool{
if (text == "\n") {
textView.resignFirstResponder()
}
return true
}
func reply() {
post?.addObject(commentView!.text, forKey: "comments")
post?.saveInBackground()
if let tmpText = commentView?.text {
comments?.append(tmpText)
}
commentView?.text = ""
println(comments?.count)
self.commentView?.resignFirstResponder()
self.commentTableView.reloadData()
}
}
I don't see anything in your code that actually fires when you click on a table cell. The way I would modify your code is to:
Implement override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {}
Use indexpath to determine the object you want to display detail for
Create a new viewcontroller for the detail, pass the object to it and then push it
A more elegant (but complex, in some ways) way of doing things is to implement PFQueryTableViewController and then use the function objectAtIndexPath() to retrieve the relevant object and display detail