Overview: How can I make it so that when the cell with the segue
identifier of 0 will load data in the row that has 0 as its ID, cell with segue identifier of 1 will load data in the row that has 1 as its ID, and so on and so forth. The data includes ID (responds to cell identifier), navTitle (title of the navigation bar), written (who the article was written by), date (date of the article), and article (the article itself).
I am trying to make it so that once a cell is tapped in my tableview it opens data unique to that cell. What would the best way to do that? I was thinking that maybe I should have it check the ID column I have on Parse and load data the data in that row, but I'm not sure how to do that. Is there a better way to do this? Any help is appreciated! Feel free to ask me for any additional information.
^ So here I have a tableview in which data is being taken from Parse and used for both labels.
^ This view controller is segued to the cell above with:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
}
}
Here is my EventsDetailViewController, the one that is called when a cell is tapped:
import UIKit
import Parse
import ParseUI
import Bolts
class EventDetailViewController: UIViewController {
#IBAction func eventDetail(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBOutlet weak var articleTitle: UILabel!
#IBOutlet weak var writtenBy: UILabel!
#IBOutlet weak var date: UILabel!
#IBOutlet weak var article: UITextView!
#IBOutlet weak var navBar: UINavigationBar!
var dateDetail = [String]()
var articleDetail = [String]()
override func viewDidLoad() {
super.viewDidLoad()
loadEvents()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadEvents () -> Void {
var query = PFQuery(className: "eventsdetail")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error : NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
var output1 = object.objectForKey("navTitle") as! String
self.navBar.topItem?.title = output1
var output2 = object.objectForKey("articleTitle") as! String
self.articleTitle.text = output2
var output3 = object.objectForKey("written") as! String
self.writtenBy.text = output3
var output4 = object.objectForKey("date") as! String
self.date.text = output4
var output5 = object.objectForKey("article") as! String
self.article.text = output5
}
}
}
}
}
}
Here is my EventsViewController:
import UIKit
import Parse
import Bolts
import ParseUI
class EventsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var timer: NSTimer!
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
var customView: UIView!
var labelsArray: Array<UILabel> = []
var refreshControl: UIRefreshControl!
var testArray = [String]()
var subArray = [String]()
#IBOutlet weak var tableview: UITableView!
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
refreshControl = UIRefreshControl()
tableview.delegate = self
tableview.dataSource = self
refreshControl.addTarget(self, action: Selector("loadEvents"), forControlEvents: UIControlEvents.ValueChanged)
self.tableview.addSubview(refreshControl)
loadEvents()
loadCustomRefreshContents()
//refreshControl colors
refreshControl.backgroundColor = UIColor.clearColor() //color of background
refreshControl.tintColor = UIColor.clearColor() //color of indicator
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadEvents () -> Void {
testArray = [String]()
subArray = [String]()
let query = PFQuery(className: "events")
let runkey = query.orderByDescending("eventTitle")
runkey.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error:NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("eventTitle") as! String
self.testArray.append(load)
let subload = object.objectForKey("date") as! String
self.subArray.append(subload)
//reload TableView
self.tableview.reloadData()
print(self.testArray)
}
}
} else {
print("error:\(error!) \(error!.userInfo)")
}
}
refreshControl.endRefreshing()
}
func do_table_refresh() {
dispatch_async(dispatch_get_main_queue()) {
self.tableview.reloadData()
return
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
}
}
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return testArray.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventcell", forIndexPath: indexPath) as! EventTableViewCell
cell.title.text = self.testArray[indexPath.row]
cell.subTitle.text = self.subArray[indexPath.row]
return cell
}
//refreshes tableview; starts refresh
func loadCustomRefreshContents() {
let refreshContents = NSBundle.mainBundle().loadNibNamed("RefreshControl", owner: self, options: nil)
customView = refreshContents[0] as! UIView
customView.frame = refreshControl.bounds
for var i=0; i<customView.subviews.count; ++i {
labelsArray.append(customView.viewWithTag(i + 1) as! UILabel)
}
refreshControl.addSubview(customView)
}
//stops refresh
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
do_table_refresh()
if refreshControl.refreshing {
if !isAnimating {
animateRefreshStep1()
}
}
}
//cycles through colors
func getNextColor() -> UIColor {
var colorsArray: Array<UIColor> = [UIColor.magentaColor(), UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
if currentColorIndex == colorsArray.count {
currentColorIndex = 0
}
let returnColor = colorsArray[currentColorIndex]
++currentColorIndex
return returnColor
}
func doSomething() {
timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "endOfWork", userInfo: nil, repeats: true)
self.do_table_refresh()
}
func endOfWork() {
refreshControl.endRefreshing()
timer.invalidate()
timer = nil
}
//first part of animation
func animateRefreshStep1() {
isAnimating = true
UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
self.labelsArray[self.currentLabelIndex].textColor = self.getNextColor()
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformIdentity
self.labelsArray[self.currentLabelIndex].textColor = UIColor.blackColor()
}, completion: { (finished) -> Void in
++self.currentLabelIndex
if self.currentLabelIndex < self.labelsArray.count {
self.animateRefreshStep1()
}
else {
self.animateRefreshStep2()
}
})
})
}
//second part of animation
func animateRefreshStep2() {
UIView.animateWithDuration(0.35, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[1].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[2].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[3].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[4].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[5].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[6].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[7].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[8].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[9].transform = CGAffineTransformMakeScale(1.5, 1.5)
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformIdentity
self.labelsArray[1].transform = CGAffineTransformIdentity
self.labelsArray[2].transform = CGAffineTransformIdentity
self.labelsArray[3].transform = CGAffineTransformIdentity
self.labelsArray[4].transform = CGAffineTransformIdentity
self.labelsArray[5].transform = CGAffineTransformIdentity
self.labelsArray[6].transform = CGAffineTransformIdentity
self.labelsArray[7].transform = CGAffineTransformIdentity
self.labelsArray[8].transform = CGAffineTransformIdentity
self.labelsArray[9].transform = CGAffineTransformIdentity
}, completion: { (finished) -> Void in
if self.refreshControl.refreshing {
self.currentLabelIndex = 0
self.animateRefreshStep1()
}
else {
self.isAnimating = false
self.currentLabelIndex = 0
for var i=0; i<self.labelsArray.count; ++i {
self.labelsArray[i].textColor = UIColor.blackColor()
self.labelsArray[i].transform = CGAffineTransformIdentity
}
}
})
})
}
}
Since you have the data on the tableView just make sure you create a segue in your storyboard connecting the prototype cell and the destination view controller and add an identifier to the segue.
Next, on the controller with the tableView make sure you call:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "segueIdentifier"){
let detailScene = segue.destinationViewController as! EventDetailViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
let row = Int(indexPath.row)
//here you can pass all the data to the destination viewController. But you CANT POPULATE YOUR LABELS. make sure you pass the data to some auxiliar variable(s). Next line is an example
detailScene.selectedData = (self.myData[row] as! PFObject)
}
}
}
Update:
detailScene.selectedData = (self.myData[row] as! PFObject)
detailScene is an instance of the destination viewController. selectedData is, in this case an instance of PFObject that will be use to populate the labels in my destination viewController. self.myData is an array in my source viewController with the data that is shown in my tableView.
So if you want to send the data you show in your cells. (
self.testArray[indexPath.row]
self.subArray[indexPath.row]
) make sure you declare the variables that will receive this data on your EventsDetailViewController something like this:
var testString:String!
var subString:String!
Then in your prepareForSegue (EventsViewController) make sure to instantiate this variables with the proper data:
detailScene.test = self.testArray[row]
detailScene.sub = self.subArray[row]
Finally on EventsDetailViewController you can pass the data to the labels you want on viewDidLoad():
self.articleTitle.text = testString
Let me know in case of any concerns.
What you are asking is the archetypical basic app: show a list of items in a tableview and being able to tap on a row to see more details.
What seems unusual to me is how you have two different classes: events and eventdetails.
Compare it with a database of books. You would not have a Book class and a BookDetails class. You would only have a Book class that contains all details about a book. So when you want to show a list of books, you fetch all the Book objects. In the tableviewcontroller you display a subset of fields from the Book objects (like i.e. title and author). When the user then taps on a specific book, you open a viewcontroller and pass it the Book object for that row. This detail viewcontroller then just shows MORE info/fields from that same Book object.
Related
I am making a chat app. When i send my messages or receive from other user they end up being displayed like this. What might be the issue? It works alright but sometimes it just changes the way the texts are displayed. Am not sure what am missing in this. Can anyone take a look at it. Kindly. Thanks in advance
Below is my code
class ChatController: UIViewController,UITextViewDelegate,UITableViewDataSource,UITableViewDelegate,UIGestureRecognizerDelegate{
#IBOutlet weak var txtViewBottomConstraints: NSLayoutConstraint!
#IBOutlet weak var viewTextViewContainer: ViewCustom!
#IBOutlet weak var txtViewContainerHeightConstraints: NSLayoutConstraint!
#IBOutlet weak var txtViewHeightConstraints: NSLayoutConstraint!
#IBOutlet var lblUserName: UILabel!
#IBOutlet var userImg: UIImageView!
#IBOutlet weak var txtView: IQTextView!
#IBOutlet weak var tblViewChat: UITableView!
#IBOutlet weak var bottomViewBottomConstraints: NSLayoutConstraint!
#IBOutlet weak var btnSend: UIButton!
var grpId = String()
var getMessageTimer: Timer!
var scrollEnable : Bool = false
var imagePicker : UIImagePickerController? = nil
var imageData : Data?
var groupName = String()
var groupImage = String()
var isFromNotification = Bool()
var strId = String()
var objChatVM = ChatViewModel()
var getMessageId = String()
var userImage:URL? = nil
var userName = String()
override func viewDidLoad() {
super.viewDidLoad()
popWithSwipe()
txtView.autocorrectionType = .no
lblUserName.text = userName
/* if userImage != nil
{
userImg.kf.setImage(with:userImage)
}
else
{
userImg.image = UIImage(named: "user")
}*/
userImg.kf.setImage(with:userImage, completionHandler: {
(image, error, cacheType, imageUrl) in
if image != nil{
self.userImg.image = image
}
else{
self.userImg.image = #imageLiteral(resourceName: "user")
}
})
IQKeyboardManager.shared.enable = false
IQKeyboardManager.shared.enableAutoToolbar = false
tblViewChat.dataSource = self
tblViewChat.delegate = self
tblViewChat.estimatedRowHeight = 70.0
tblViewChat.rowHeight = UITableViewAutomaticDimension
txtView.delegate = self
// txtView.textContainerInset = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: 2)
let tapGestuer = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
view.addGestureRecognizer(tapGestuer)
tapGestuer.delegate = self
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
if getMessageTimer != nil{
getMessageTimer.invalidate()
}
getMessageTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(getMessageApi), userInfo: nil, repeats: true)
IQKeyboardManager.shared.enable = false
IQKeyboardManager.shared.enableAutoToolbar = false
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
getMessageTimer.invalidate()
NotificationCenter.default.removeObserver(self)
}
// MARK:- Get messages from server
#objc func getMessageApi(){
objChatVM.getMessage(param:strId) {status in
if status{
self.tblViewChat.reloadData()
if(self.objChatVM.getNumberOfMessage() != 0){
self.tblViewChat.scrollToRow(at: IndexPath(item: self.objChatVM.getNumberOfMessage()-1, section: 0), at: .bottom, animated: false)
}
}
}
}
#objc func handleTap(sender: UITapGestureRecognizer) {
txtView.resignFirstResponder()
}
// Enable IQKEYBoard manager here for handle keyboard at other controller which has disabled in viewdidload or viewwillappear
override func viewDidDisappear(_ animated: Bool) {
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.enableAutoToolbar = true
}
// MARK:- Gesutrue Delegate Methods
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
// Handle here tap on table view and inside cell for dismiss keyboard while tap outside on the screen
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if (touch.view is SenderTblCell || touch.view is ReceiverTblCell ) {
return false
}
if (touch.view?.superview is SenderTblCell || touch.view?.superview is ReceiverTblCell) {
return false
}
if (touch.view?.superview?.superview is SenderTblCell || touch.view?.superview?.superview is ReceiverTblCell) {
return false
}
if (touch.view?.superview?.superview?.superview is SenderTblCell || touch.view?.superview?.superview?.superview is ReceiverTblCell) {
return false
}
if(touch.view?.superview?.isDescendant(of: SenderTblCell().contentView))! || (touch.view?.superview?.isDescendant(of: ReceiverTblCell().contentView))!{
return false
}
return true // handle the touch
}
// MARK:- KeyBoard will show
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
var safeArea = 0
if UIDevice().userInterfaceIdiom == .phone || UIDevice().userInterfaceIdiom == .pad{
switch UIScreen.main.nativeBounds.height {
case 2436:
bottomViewBottomConstraints.constant = -keyboardSize.height + 30
self.view.layoutIfNeeded()
default:
if #available(iOS 11.0, *) {
let window = UIApplication.shared.keyWindow
safeArea = Int(window?.safeAreaInsets.bottom ?? 0.0)
}
bottomViewBottomConstraints.constant = -keyboardSize.height + CGFloat(safeArea) - 10
self.view.layoutIfNeeded()
}
}
}
}
// MARK:- KeyBoard will hide
#objc func keyboardWillHide(notification: NSNotification) {
bottomViewBottomConstraints.constant = -30
self.view.layoutIfNeeded()
}
#IBAction func btnSendAction(_ sender: Any) {
let param = ["userId":strId,"message":txtView.text!]
objChatVM.sendMessage(param: param) { (status) in
self.txtView.text = ""
self.textViewDidChange(self.txtView)
}
}
//MARK:- TextView Delegate Methods
func textViewDidChange(_ textView: UITextView) {
if textView.text == ""{
//textView.translatesAutoresizingMaskIntoConstraints = true
// txtViewHeightConstraints.constant = 100.0
// btnSend.setImage(#imageLiteral(resourceName: "attachment"), for: .normal)
}else{
// btnSend.setImage(#imageLiteral(resourceName: "sendMsg"), for: .normal)
}
var frame : CGRect = textView.bounds
frame.size.height = textView.contentSize.height
print(frame)
if(frame.height >= 100.0){
textView.isScrollEnabled = true
}
else{
textView.isScrollEnabled = false
txtView.frame.size = frame.size
}
if textView.text == ""{
txtViewContainerHeightConstraints.constant = 50.0
txtViewBottomConstraints.constant = 5.0
txtView.updateConstraints()
viewTextViewContainer.updateConstraintsIfNeeded()
viewTextViewContainer.updateConstraints()
viewTextViewContainer.layoutIfNeeded()
self.view.layoutIfNeeded()
}
}
func textViewDidEndEditing(_ textView: UITextView) {
}
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
return true
}
// MARK:- TableView DataSource and Delegate Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objChatVM.getNumberOfMessage()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let messageUserId = objChatVM.getMessageUserFromId(index: indexPath.row)
print(UserViewModel.Shared().getUserId())
if(messageUserId == UserViewModel.Shared().getUserId()){
let cell = tblViewChat.dequeueReusableCell(withIdentifier: "senderCell") as! SenderTblCell
cell.lblMessage.text = objChatVM.getMessage(index: indexPath.row)
cell.lblDate.text = objChatVM.getDateTime(index: indexPath.row)
return cell
}
let cell = tblViewChat.dequeueReusableCell(withIdentifier: "receiverCell") as! ReceiverTblCell
cell.lblMessage.text = objChatVM.getMessage(index: indexPath.row)
cell.lblDate.text = objChatVM.getDateTime(index: indexPath.row)
cell.lblName.text = objChatVM.getFullNameOfUserFrom(index: indexPath.row)
let url = URL(string:objChatVM.getUserFromImage(index:indexPath.row))
cell.imgView.kf.indicatorType = .activity
cell.imgView.kf.setImage(with:url)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
txtView.resignFirstResponder()
}
// MARK: Side Menu Button Action
#IBAction func btnSideMenuActn(_ sender: UIButton) {
self.pushViewControl(ViewControl:"SideMenuController")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is how the message from my server in my logs looks like
message = "Am+good.+How+are+you+my+student%3F";
Use removingPercentEncoding and some of the text such as + doesn't seem to generated by urlEncoding if they are created by code then use both in combination:
message = "Am+good.+How+are+you+my+student%3F"
let decodedMessage = message.removingPercentEncoding?.replacingOccurrences(of: "+", with: " ")
print(decodedMessage)
I am trying to make an app that connects to chromecast to play a video on TV, up till now I am still trying to display the video links using two view controllers, one contains a webview that makes the user gets the video page, the other is to display all video links inferred from the first view to make the user select which video to cast from the page. I am able to get the links but the problem is it doesn't want to be displayed in the table view cells. I have tried many methods but I noticed, for some reason the UITableViewDataSource methods are not being called at all. Here is the code:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
//MARK: Outlets
#IBOutlet weak var searchBar: UITextField!
#IBOutlet weak var webView: UIWebView!
#IBOutlet weak var cancelButton: UIButton!
#IBOutlet weak var searchBarTrailingConstraint: NSLayoutConstraint!
//MARK: Properties
static var videoURLs: [String] = []
//MARK: Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
cancelButton.layer.cornerRadius = 5
cancelButton.isHidden = true
webView.delegate = self
}
func webViewDidFinishLoad(_ webView: UIWebView) {
var videoTag = ""
var embedTag = ""
let htmlCode = webView.stringByEvaluatingJavaScript(from: "document.documentElement.outerHTML")
let htmlTags = htmlCode!.components(separatedBy: "\n") as [String]
for tag in htmlTags{
var videoURL = ""
if tag.contains("<video") {
videoTag = tag.substring(from: tag.range(of: "<video")!.lowerBound)
videoTag = videoTag.substring(to: (videoTag.range(of: ">")?.upperBound)!)
if videoTag.contains("src"){
videoTag = tag.substring(from: tag.range(of: "src")!.upperBound)
for x in videoTag.characters{
if x == "\""{
continue
}else if x == "="{
continue
}else if x == ">"{
break
}else{
videoURL.append(x)
}
}
}
ViewController.videoURLs.append(videoURL)
}
if tag.contains("<embed") {
embedTag = tag.substring(from: tag.range(of: "<embed")!.lowerBound)
embedTag = embedTag.substring(to: (embedTag.range(of: ">")?.upperBound)!)
if embedTag.contains("src"){
embedTag = tag.substring(from: tag.range(of: "src")!.upperBound)
for x in embedTag.characters{
if x == "\""{
continue
}else if x == "="{
continue
}else if x == ">"{
break
}else{
videoURL.append(x)
}
}
}
ViewController.videoURLs.append(videoURL)
}
}
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "Done")))
}
//MARK: Actions
#IBAction func cancelPressed() {
cancelButton.isHidden = true
searchBarTrailingConstraint.constant = 0.0
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
searchBar.resignFirstResponder()
}
#IBAction func searchBarPressed() {
searchBarTrailingConstraint.constant = (cancelButton.frame.width + 8.0) * -1
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
cancelButton.isHidden = false
}
#IBAction func returnButtonPressed(_ sender: UITextField) {
cancelPressed()
if let url = URL(string: sender.text!){
if UIApplication.shared.canOpenURL(url){
let request = URLRequest(url: url)
webView.loadRequest(request)
}else{
let googleSearchURL = URL(string: "https://www.google.com/search?client=safari&q=\(url)&ie=UTF-8&oe=UTF-8")
let request = URLRequest(url: googleSearchURL!)
webView.loadRequest(request)
}
}else{
var searchString: [String] = []
var searchWord = ""
for x in (sender.text?.characters)!{
if x == " "{
searchString.append(searchWord)
searchWord = ""
}else{
searchWord.append(x)
}
}
//For appending the last word not followed by a space
if !(searchString.last == searchWord){
searchString.append(searchWord)
}
var googleSearchURL = "https://www.google.com/search?client=safari&ie=UTF-8&oe=UTF-8&q="
for element in searchString{
googleSearchURL.append(element)
if !(searchString.last == element){
googleSearchURL.append("+")
}
}
let request = URLRequest(url: URL(string:googleSearchURL)!)
webView.loadRequest(request)
}
}
#IBAction func backButtonPressed(_ sender: UIButton) {
if webView.canGoBack{
webView.goBack()
}
}
#IBAction func forwardButtonPressed(_ sender: UIButton) {
if webView.canGoForward {
webView.goForward()
}
}
}
MediaTableViewController:
import UIKit
import AVFoundation
class MediaTableViewController: UIViewController, UITableViewDataSource {
var videoURLs: [String] = []
var videoScreenshots: UIImage!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(MediaTableViewController.replyToNotification), name: nil, object: nil)
self.tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videoURLs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("NOW!\n\n\n", indexPath.count)
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MediaTableViewCell
cell.videoImage.image = videoScreenshot(url: videoURLs[indexPath.count])
cell.videoURL.text = videoURLs[indexPath.count]
return cell
}
#objc func replyToNotification(){
videoURLs = ViewController.videoURLs
ViewController.videoURLs = []
}
// MARK: - Table view data source
func videoScreenshot(url: String) -> UIImage? {
let asset = AVURLAsset(url: URL(string: url)!)
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
do {
let imageRef = try generator.copyCGImage(at: CMTime(value: asset.duration.value/2, timescale: asset.duration.timescale), actualTime: nil)
return UIImage(cgImage: imageRef)
}
catch let error as NSError
{
print("Image generation failed with error \(error)")
return nil
}
}
}
MediaTableViewCell.swift:
import UIKit
class MediaTableViewCell: UITableViewCell {
#IBOutlet weak var videoImage: UIImageView!
#IBOutlet weak var videoURL: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
Here is the Main.storyboard:
You do not call reloadData() thus the tableView is idle.
To fix this the following to MediaTableViewController:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
As I see you didn't implement tableView delegate
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(MediaTableViewController.replyToNotification), name: nil, object: nil)
self.tableView.delegate = self
self.tableView.dataSource = self
}
then add this method to your controller
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
hope this will help
Swift
I'm trying to make it so when you pull to refresh on the tableview it updates the tableview with the data that is stored on Parse.com
I've researched this and it seems I need to use loadObjects()
When I place this in it says: "Use of unresolved identifier 'loadObjects'
Not sure if this is what I need or not..
Here is my ViewController.swift
import UIKit
import Parse
import Bolts
import ParseUI
class EventsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var timer: NSTimer!
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
var customView: UIView!
var labelsArray: Array<UILabel> = []
var refreshControl: UIRefreshControl!
var testArray = [String]()
var subArray = [String]()
#IBOutlet weak var tableview: UITableView!
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
tableview.delegate = self
tableview.dataSource = self
refreshControl = UIRefreshControl()
tableview.addSubview(refreshControl)
loadCustomRefreshContents()
//refreshControl colors
refreshControl.backgroundColor = UIColor.clearColor() //color of background
refreshControl.tintColor = UIColor.clearColor() //color of indicator
let query = PFQuery(className: "events")
let runkey = query.orderByDescending("eventTitle")
runkey.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error:NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("eventTitle") as! String
self.testArray.append(load)
let subload = object.objectForKey("date") as! String
self.subArray.append(subload)
print(self.testArray)
}
}
} else {
print("error:\(error!) \(error!.userInfo)")
}
}
sleep(3)
do_table_refresh()
loadViewIfNeeded()
loadObjects()
/*let url = NSURL(string: "https://m.facebook.com/CathedralCityMunicipal")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {
(data, response, error) in
if error == nil {
let urlContent = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(urlContent)
dispatch_async(dispatch_get_main_queue()) {
self.webView.loadHTMLString(urlContent! as String, baseURL: nil)
}
}
}
task.resume()*/
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func do_table_refresh() {
dispatch_async(dispatch_get_main_queue()) {
self.tableview.reloadData()
return
}
}
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return testArray.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("eventcell", forIndexPath: indexPath) as! EventTableViewCell
cell.title.text = self.testArray[indexPath.row]
cell.subTitle.text = self.subArray[indexPath.row]
return cell
}
//refreshes tableview; starts refresh
func loadCustomRefreshContents() {
let refreshContents = NSBundle.mainBundle().loadNibNamed("RefreshControl", owner: self, options: nil)
customView = refreshContents[0] as! UIView
customView.frame = refreshControl.bounds
for var i=0; i<customView.subviews.count; ++i {
labelsArray.append(customView.viewWithTag(i + 1) as! UILabel)
}
refreshControl.addSubview(customView)
do_table_refresh()
}
//stops refresh
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
do_table_refresh()
if refreshControl.refreshing {
if !isAnimating {
doSomething()
animateRefreshStep1()
self.do_table_refresh()
}
}
}
//cycles through colors
func getNextColor() -> UIColor {
var colorsArray: Array<UIColor> = [UIColor.magentaColor(), UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
if currentColorIndex == colorsArray.count {
currentColorIndex = 0
}
let returnColor = colorsArray[currentColorIndex]
++currentColorIndex
return returnColor
}
func doSomething() {
timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "endOfWork", userInfo: nil, repeats: true)
self.do_table_refresh()
}
func endOfWork() {
refreshControl.endRefreshing()
self.do_table_refresh()
timer.invalidate()
timer = nil
}
//first part of animation
func animateRefreshStep1() {
isAnimating = true
UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
self.labelsArray[self.currentLabelIndex].textColor = self.getNextColor()
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformIdentity
self.labelsArray[self.currentLabelIndex].textColor = UIColor.blackColor()
}, completion: { (finished) -> Void in
++self.currentLabelIndex
if self.currentLabelIndex < self.labelsArray.count {
self.animateRefreshStep1()
}
else {
self.animateRefreshStep2()
}
})
})
}
//second part of animation
func animateRefreshStep2() {
UIView.animateWithDuration(0.35, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[1].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[2].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[3].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[4].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[5].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[6].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[7].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[8].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[9].transform = CGAffineTransformMakeScale(1.5, 1.5)
}, completion: { (finished) -> Void in
UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
self.labelsArray[0].transform = CGAffineTransformIdentity
self.labelsArray[1].transform = CGAffineTransformIdentity
self.labelsArray[2].transform = CGAffineTransformIdentity
self.labelsArray[3].transform = CGAffineTransformIdentity
self.labelsArray[4].transform = CGAffineTransformIdentity
self.labelsArray[5].transform = CGAffineTransformIdentity
self.labelsArray[6].transform = CGAffineTransformIdentity
self.labelsArray[7].transform = CGAffineTransformIdentity
self.labelsArray[8].transform = CGAffineTransformIdentity
self.labelsArray[9].transform = CGAffineTransformIdentity
}, completion: { (finished) -> Void in
if self.refreshControl.refreshing {
self.currentLabelIndex = 0
self.animateRefreshStep1()
}
else {
self.isAnimating = false
self.currentLabelIndex = 0
for var i=0; i<self.labelsArray.count; ++i {
self.labelsArray[i].textColor = UIColor.blackColor()
self.labelsArray[i].transform = CGAffineTransformIdentity
}
}
})
})
}
/*
// 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.
}
*/
}
I have tried letting the do_table_refresh() function run after the refresh is over, but the tableview does not update. I have also tried using self.tableview.reloadData() but also does not work.
I'm not sure what I am doing wrong, any help is greatly appreciated!
Feel free to ask me for any additional information!
Thank you for your time!
So, if you are trying to get the Parse data everytime you to pull-to-refresh you should query for them always.
Keep your query into a single function and call a tableView.reloadData() so it will reload the tableView every time you query your events:
func loadEvents () -> Void {
self.testArray = []
self.subArray = []
let query = PFQuery(className: "events")
let runkey = query.orderByDescending("eventTitle")
runkey.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error:NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("eventTitle") as! String
self.testArray.append(load)
let subload = object.objectForKey("date") as! String
self.subArray.append(subload)
//reload TableView
self.tableView.reloadData()
print(self.testArray)
}
}
} else {
print("error:\(error!) \(error!.userInfo)")
}
}
refreshControl.endRefreshing()
}
And then add a Target for your UIRefreshControl inside your ViewDidLoad()
refreshControl.addTarget(self, action: Selector("loadEvents"), forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refreshControl)
Also, you must declare your UIRefreshControl as follows:
var refreshControl = UIRefreshControl()
I am working on making a social media app clone using tutorials for practice in Swift, but I want to add a like button with Parse but not sure how. Does anyone know a tutorial or do you know how you would go about doing this? I attempted to make one like this but I'm pretty sure it is not correct...
I put this in the cell view controller
#IBAction func likeButton(sender: AnyObject) {
a++
var post = PFObject(className: "Post")
post["likes"] = a
}
}
This went into the feed view controller...
var messages = [String]()
var usernames = [String]()
var imageFiles = [PFFile]()
var users = [String: String]()
var likesArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
self.likesArray.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
self.users[user.objectId!] = user.username!
}
}
}
})
var getFollowedUsersQuery = PFQuery(className: "followers")
getFollowedUsersQuery.whereKey("follower", equalTo: PFUser.currentUser()!.objectId!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
var followedUser = object["following"] as! String
var query = PFQuery(className: "Post")
query.whereKey("userId", equalTo: followedUser)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.messages.append(object["message"] as! String)
self.imageFiles.append(object["imageFile"] as! PFFile)
self.usernames.append(self.users[object["userId"] as! String]!)
self.likesArray.append(object["likes"] as? String)
self.tableView.reloadData()
}
}
})
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
imageFiles[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
myCell.username.text = usernames[indexPath.row]
myCell.message.text = messages[indexPath.row]
myCell.likeLabel.text = likesArray[indexPath.row]
myCell.selectionStyle = .None
return myCell
}
}
This is the view controller when you post the picture and message...
var likes = 0
var picSelected = false
#IBOutlet var feed: UIButton!
func displayAlert(title: String, message: String) {
var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
}))
presentViewController(alert, animated: true, completion: nil)
}
var activityIndicator = UIActivityIndicatorView()
#IBOutlet var imageToPost: UIImageView!
#IBAction func chooseImage(sender: AnyObject) {
var image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
image.allowsEditing = false
presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
picSelected = true
}
#IBOutlet var message: UITextField!
#IBAction func postImage(sender: AnyObject) {
if message.text != "" && picSelected != false {
picSelected = false
activityIndicator = UIActivityIndicatorView(frame: view.frame)
activityIndicator.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
var post = PFObject(className: "Post")
post["message"] = message.text
post["userId"] = PFUser.currentUser()?.objectId!
let imageData = UIImagePNGRepresentation(imageToPost.image)
let imageFile = PFFile(name: "image.png", data: imageData)
post["imageFile"] = imageFile
post["likes"] = a
post.saveInBackgroundWithBlock { (success, error) -> Void in
self.activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
if error == nil {
self.displayAlert("Image Posted!", message: "Your image has been posted successfully.")
self.imageToPost.image = UIImage(named: "Blank-Person1.png")
self.message.text = ""
}
}
} else {
displayAlert("Could Not Post Image!", message: "Please enter a message and/or select a picture.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// 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.
}
*/
}
I'm about to make Like button like this:
Create Names column in parse ( Array column) to hold names who click on like button
Create Likes column in parse (integer column) to hold count number of Names column
and when someone click on like button add his name to Names Array in parse, If he click it again remove his name
And you need to take all names in NamesArray column and count them in swift then update likes column
i'm not sure but that's in my mind right now, but if you think of it you'll get better way.
private let DBItemCellIdentifier = "ItemCellIdentifier"
private let DBItemSegueIdentifier = "ItemSegueIdentifier"
class DBItemsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, DBItemTableViewCellDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var previousButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var categoryNameLabel: UILabel!
private var elements = [Any]()
private var currentItemIndex = 0
private var isFetching = false
private weak var currentCategory: DBCategory? {
didSet {
updateView()
}
}
var categories = [DBCategory]()
var currentCategoryIndex = 0
//MARK: - Class Methods
//MARK: - Initialization
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100.0
tableView.tableFooterView = UIView(frame: CGRectZero)
setupUserAndCartButtons()
fetchItems()
}
deinit {
print("deinit")
}
//MARK: - Actions
#IBAction func nextButtonTapped(sender: UIButton) {
currentCategoryIndex = min(currentCategoryIndex + 1, categories.count - 1)
fetchItems()
}
#IBAction func previousButtonTapped(sender: UIButton) {
currentCategoryIndex = max(currentCategoryIndex - 1, 0)
fetchItems()
}
//MARK: - Private
private func fetchItems() {
tableView.alpha = 0
currentCategory = nil
if !categories.isEmpty && !isFetching {
let category = categories[currentCategoryIndex]
currentCategory = DBCategory.findCategoryWithIdentifier(category.identifier)
if currentCategory == nil {
SVProgressHUD.show()
}
isFetching = true
DBNetworkClient.sharedClient().itemsForCategory(category, completionBlock: { error in
defer {
self.isFetching = false
SVProgressHUD.dismiss()
UIAlertController.showAlertFromError(error)
}
self.currentCategory = DBCategory.findCategoryWithIdentifier(category.identifier)
})
}
}
private func updateView() {
let category = categories[currentCategoryIndex]
title = category.menu.location.name
categoryNameLabel.text = category.name
previousButton.hidden = currentCategoryIndex == 0 ? true : false
nextButton.hidden = currentCategoryIndex == categories.count - 1 ? true : false
prepareElements()
tableView.reloadData()
UIView.animateWithDuration(0.5, animations: {
self.tableView.alpha = 1
})
}
private func prepareElements() {
elements.removeAll(keepCapacity: false)
if let items = currentCategory?.items {
for item in items {
elements.append(item)
}
}
if let sets = currentCategory?.sets {
for set in sets {
elements.append(set)
}
}
elements.sortInPlace {
let left = ($0 as? DBSet)?.position ?? ($0 as? DBItem)?.position
let right = ($1 as? DBSet)?.position ?? ($1 as? DBItem)?.position
return left < right
}
}
//MARK: - Overridden
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let element = elements[currentItemIndex]
if segue.identifier == DBItemSegueIdentifier {
let itemViewController = segue.destinationViewController as! DBItemViewController
itemViewController.prepareWithElement(element)
}
}
//MARK: - UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0 //when I change to elements.count, deinit is not called
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(DBItemCellIdentifier, forIndexPath: indexPath) as! DBItemTableViewCell
let element = elements[indexPath.row]
if let item = element as? DBItem {
cell.configureCellWithItem(item)
} else if let set = element as? DBSet {
cell.configureCellWithSet(set)
}
cell.delegate = self
return cell
}
//MARK: - UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
currentItemIndex = indexPath.row
performSegueWithIdentifier(DBItemSegueIdentifier, sender: tableView.cellForRowAtIndexPath(indexPath))
}
//MARK: - DBItemTableViewCellDelegate
func itemTableViewCell(cell: DBItemTableViewCell, willPresentSetGroupsViewControllerForSet set: DBSet) {
presentSetOrderControllerWithOrder(DBSetOrder(set: set))
}
func itemTableViewCell(cell: DBItemTableViewCell, willPresentItemMealSizesViewControllerForItem item: DBItem) {
presentItemOrderControllerWithOrder(DBItemOrder(item: item))
}
}
Why my deinit is not called. I will offer 100 bounty once I will be able to do this, and award to that one, who help me solve this problem... I will offer a bounty even after solving the problem.
VERY IMPORTANT INFO:
this code calls deinit. IT IS WORKING. Because number of rows is 0. But I need to have there elements.count. When I change to this, deinit is not called.
EDIT:
func itemsForCategory(category: DBCategory, completionBlock: DBErrorHandler) {
let query = "locations/" + category.menu.location.identifier + "/categories/" + category.identifier
GET(query, parameters: nil, success: { operation, response in
if let error = NSError(response: response) {
completionBlock(error)
} else {
self.coreDataAssistant.parseAndSaveItemsToPersistentStore(response as? NSDictionary, completionBlock: { error in
completionBlock(error)
})
}
}) { operation, error in
let responseError = NSError(response: operation.responseObject)
completionBlock(responseError ?? error)
}
}
You are assigning self as your table view cell's delegate:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(DBItemCellIdentifier, forIndexPath: indexPath) as! DBItemTableViewCell
let element = elements[indexPath.row]
if let item = element as? DBItem {
cell.configureCellWithItem(item)
} else if let set = element as? DBSet {
cell.configureCellWithSet(set)
}
// HERE
cell.delegate = self
return cell
}
The cell's delegate property is defined as follows:
var delegate: DBItemTableViewCellDelegate?
This creates a strong reference between the cell and the delegate (your view controller). The cell is also retained by the table view. This creates a retain cycle.
You will need to change the definition of the delegate property to be weak:
weak var delegate: DBItemTableViewCellDelegate?
Edit based on comment:
Your DBItemTableViewCellDelegate definition will need to be defined as a class-only protocol
protocol DBItemTableViewCellDelegate: class {
...
}