Update particular row in tableviewcell in tableview in swift 3? - uitableview

I am using tableviewcell.xib in table view. In that I have comment button, if I click on that I will navigate to another page so that I can comment, when I dismiss after commenting. It will come to tableview page, in that I want to update the comment count value without updating with service call . where I should add this code for updating cell.Please help me.
let indexPath = IndexPath(item: sender.tag, section: 0)
self.tableView.reloadRows(at: [indexPath], with: .automatic)
I am navigating like this
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let commentPage = storyBoard.instantiateViewController(withIdentifier: "postCommentsPage") as! PostCommentViewController
self.present(commentPage, animated: false, completion:nil)

What you need to do is to make one protocol like UpdateCommentCount and implement that protocol with your Controller where you are having this tableView after that in your PostCommentViewController make one instance property of type UpdateCommentCount, also in your tableController declare one property of type Int to hold the reference of tapped row.
protocol UpdateCommentCount {
func updateComment(with count:Int)
}
Now implement this UpdateCommentCount with yourController and add one Int property to hold the reference of tapped row and set it inside your button action where you are presenting your PostCommentViewController
class YourController: UIViewController, UpdateCommentCount, UITableViewDelegate, UITableViewDataSource {
var currentCommentRow = 0
//Your other methods
func commentButtonAction(_ sender: UIButton) {
currentCommentRow = sender.tag
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let commentPage = storyBoard.instantiateViewController(withIdentifier: "postCommentsPage") as! PostCommentViewController
commentPage.commentDelegate = self
self.present(commentPage, animated: false, completion:nil)
}
func updateComment(with count:Int) {
let dic = yourArray[self.currentCommentRow]
dic["commentCount"] = count
yourArray[self.currentCommentRow] = dic
let indexPath = IndexPath(item: self.currentCommentRow, section: 0)
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
Now in PostCommentViewController declare one instance property named commentDelegate of type UpdateCommentCount and after simply call its delegate method when you successfully post comment.
var commentDelegate: UpdateCommentCount
Call updateComment after successfully posting new comment.
commentDelegate.updateComment(with: newCount)

You can use NSNotification. Register the notification in that table view's viewDidLoad method. Than send notification before presenting the view as shown bellow..
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let commentPage = storyBoard.instantiateViewController(withIdentifier: "postCommentsPage") as! PostCommentViewController
NotificationCenter.default.post(name: Notification.Name(rawValue: myNotificationKey), object: self)
self.present(commentPage, animated: false, completion:nil)
Than reload table view in notification calling function.

Related

How can i pop back from storyboard of framework?

let storyboardBundle = Bundle(identifier: "SignUPFramework")
let vc = UIStoryboard.init(name: "SignIn", bundle: storyboardBundle).instantiateViewController(withIdentifier: "SignInViewcontroller") as! SignInViewcontroller
navigationController?.pushViewController(vc, animated: true)
I have navigated to storyboard of framework as above.
You own the navigationController. So you can use either popViewController(animated:) (if you are sure that there is only one view controller you wish to pop), or popToViewController(_:animated:), or popToRootViewController(animated:) (if you wish to return to the root).
It does not matter that the storyboard is in a framework. You still own the view hierarchy, the navigation stack and the view controller instance you get from the below line of code
let vc = UIStoryboard.init(name: "SignIn", bundle: storyboardBundle).instantiateViewController(withIdentifier: "SignInViewcontroller") as! SignInViewcontroller
So you can do whatever you want with it in terms of navigation (push it and pop it or present it and dismiss it).
You just need to identify at what point you want to trigger any of these actions.
I think you are using xib so it will not return action first you should do protocol for callback to view controller then you can use popViewController(animated:).
protocol CallBackDelegate: AnyObject {
func back()
}
//Delegate
weak var delegate:CallBackDelegate?
#IBAction func buttonAction(_ sender: Any) {
delegate?.back()
}
Now you can use protocol in view controller
class ViewController: UIViewController, CallBackDelegate {
func back() {
navigationController?.popViewController(animated: true)
}
}
Note :- Confirm delegate variable in cellForRowAtIndexPath i.e.
cell.delegate = self
I have solved it by
let bundle = Bundle(for: SignInViewcontroller.self)
let vc = UIStoryboard.init(name: "SignIn", bundle: bundle).instantiateViewController(withIdentifier: "SignInViewcontroller") as! SignInViewcontroller
in above snippet instead of passing bundle id i have passed viewcontroller itself.

Pushing Data to Another ViewController Without Moving ViewControllers

I am relatively new to coding in Swift. I am trying to pass data back to another view controller without having to segue to that controller so that the user can stay on the same screen. I am looking into using a delegate and wondering if this will be the best way to access the variable on multiple view controllers. Thank you
View controller 1:
func passVariables() {
let passSleepValue = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbHome") as! sbHomeController
passSleepValue.getSleepValue = sleepValue
//navigationController?.pushViewController(passSleepValue, animated: true)
}
View Controller 2:
func updateDay() {
let dayScoreAvg = getSleepValue
dayScore.text = String(format: "%.1f", dayScoreAvg)
print("Get sleep Value is \(getSleepValue)")
}
It looks like you can already pass data to second ViewController but you can't pass some data back.
So one way is using delegate pattern.
Start with declaring delegate protocol with method for passing data (in your case it can be just passing String)
protocol SecondVCDelegate: class {
func passText(_ text: String)
}
then create delegate variable in second ViewController
class SecondViewController: UIViewController {
weak var delegate: SecondVCDelegate?
...
}
Now you can implement this protocol to first ViewController
extension ViewController: SecondVCDelegate {
func passText(_text: String) {
// do something with text passed from second VC
}
}
now set delegate of Second VC as self before you push it
func passVariables() {
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbHome") as! sbHomeController
viewController.getSleepValue = sleepValue
viewController.delegate = self
navigationController?.pushViewController(viewController, animated: true)
}
then in second VC you can just call method on your delegate and in first VC this method gets called
delegate?.passText("Hello First!")

How to show different view controller on did select of collectionv view cell

I have 3 view controllers called firstvc, secondvc, thirdvc. And I have one collection view which will scroll horizontally. I have done that. And if I select any cell, it will print which index path it was. It's fine, no problem. So in my mainviewcontroller I have one collection view which will scroll horizontally. And there is one UIView called myview. Whenever I press any cell, I get its indexPath. I need to show my 3 view controllers as subviews of myview in my mainviewcontroller.
My code so far:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
if indexPath.item == 0 {
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
self.contentSubView.addSubview(allCollectionViewController)
} else if indexPath.item == 1 {
} else if indexPath.item == 2 {
}
}
}
I am getting error on this line :
self.contentSubView.addSubview(allCollectionViewController)
Cannot convert value of type 'firstvc' to expected argument type 'UIView'
How do i solve this issues.
Thanks in advance !!
UPDATED:
if indexPath.item == 0 {
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
self.contentSubView.addSubview(allCollectionViewController.view)
} else if indexPath.item == 1 {
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
if let allCollec = alertStoryBoard.instantiateViewController(withIdentifier:"secondvc") as? secondvc {
self.contentSubView.addSubview(allCollec.view)
}else if indexPath.item == 2 {
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
if let wController = alertStoryBoard.instantiateViewController(withIdentifier:"Thirdvc") as? Thirdvc {
self.contentSubView.addSubview(wController.view)
}
Only showing first vc class alone, not showing second and third one. Also, why i am following lk this means. When ever i press on any collection view cell, that particular class view controlelr have to show in my sub view of uiview in my mainviewcontroller
In my first view controller i placed one uiview with some background color .But that not at all showing .Its showing whitee color.That too not showing correctly
you can push present viewcontroller but you can't add viewcontroller as subview.
If you want to add as subview then you can do like,
self.contentSubView.addSubview(allCollectionViewController.view)
or push viewcontroller if you have navigation controller like
navigationController?.pushViewController(allCollectionViewController, animated: true)
or present it like
present(allCollectionViewController, animated: true) {
}
//Do this:
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "someViewController")
self.present(controller, animated: true, completion: nil)
//You have to present your view controller and what you are doing is adding it as a sub view.
do like
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
based on your comment remove the subviews before add on your myview
for subview in contentSubView.subviews {
subview.removeFromSuperview()
}
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
var controller: UIViewController!
if indexPath.item == 0 {
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
controller = allCollectionViewController
}
} else if indexPath.item == 1 {
if let allCollec = alertStoryBoard.instantiateViewController(withIdentifier:"secondvc") as? secondvc {
controller = allCollec
}
}else if indexPath.item == 2 {
if let wController = alertStoryBoard.instantiateViewController(withIdentifier:"Thirdvc") as? Thirdvc {
controller = wController
}
}
addChildViewController(controller)
// Add the child's View as a subview
contentSubView.addSubview(controller.view)
controller.view.frame = contentSubView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tell the childviewcontroller it's contained in it's parent
controller.didMove(toParentViewController: self)
}
The error is very obvious. You can only use addSubview according to this definition:
open func addSubview(_ view: UIView)
If you want to use multiple view controllers in one view controller, I would recommend using container view controllers.
Try this tutorial: https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/
Otherwise a simple approach is to use:
self.contentSubView.addSubview(allCollectionViewController.view)
You can then use constraints on the view to manage multiple view controllers.

How to call another controller on long press of UITableViewCell in swift?

I am using the below code to display MyEditViewController but all the field outlets in MyEditViewController are nil because of this line let editController = MyEditViewController(). Here I am creating new instance. So outlets are nil now. Is there any other way to call the edit controller without creating instance of it?
#IBAction func editMethod(sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.Began {
let cell = sender.view as! MyTableViewCell
let editController = MyEditViewController()
editController.sample= samples[cell.tag]
presentViewController(editController, animated: true, completion: nil)
}
}
To instantiate a new controller with your outlets you can use a xib
let editController = MyEditViewController(nibName: "MyEditViewController", bundle: nil)
Or you can attribute a StoryboardId to your controller and use with instantiateViewControllerWithIdentifier
let editController = storyboard?.instantiateViewControllerWithIdentifier("MyEditViewControllerStoryboardId") as! MyEditViewController
Or as a suggestion for your case, you can use a different approach using storyboard segues. Read more about it here
performSegueWithIdentifier("PresentMyEditController", sender: self)
You should initiate not a Class, you shoud initiate it as an ViewController from Storyboard. So in your case set an "Storyboard-ID" for your Controller.
And then use:
let editController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("StoryboardID") as! MyEditViewController
So all outlets should work fine.

Swift: How can I make UITextView in UITableViewCell firstresponder

I have searched (so far unsuccessfully) for an (understandable) solution to this problem. My app uses UITableViews with cells that contain UITextViews. I want to be able to select the UITextView rather than the underlying cell. I understand that I need to make it the firstresponder but cannot find out how to do this. I am using Swift 2.
Update - my code
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:NSIndexPath)
{
switch (getTipsInfo(viewName, sectionNumber: indexPath.section, tipOrder: indexPath.row).tipType) {
case "URL":
defaults.setObject(getTipsInfo(viewName, sectionNumber: indexPath.section, tipOrder: indexPath.row).tipLinkName, forKey: "URL")
myStack.push(getViewNC(viewName))
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc : UIViewController = storyboard.instantiateViewControllerWithIdentifier(browserNC)
self.presentViewController(vc, animated: true, completion: nil)
case "link":
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
myStack.push(getViewNC(viewName))
let vc : UIViewController = storyboard.instantiateViewControllerWithIdentifier(getTipsInfo(viewName, sectionNumber: indexPath.section, tipOrder: indexPath.row).tipLinkName)
self.presentViewController(vc, animated: true, completion: nil)
default:
()
} // end switch
}
Assuming that you want to make this UITextView the first responder immediately upon it loading, you could put the following code inside of your awakeFromNib method inside of a custom UITableViewCell class.
self.myTextView.becomeFirstResponder()
This will make it so that the cursor will automatically be inside of myTextView whenever this cell loads, and the keyboard will come up as well.

Resources