Populate table view from different Swift file - ios

I am having Search view Controller:
Refer This Image .
In this image you can see it has tableview, search_textfiled and advance search button. So if I put some text in search field and click on search icon it use to fire query and it is populating the result in the table. But when clicking on Advance search it use to open one popover, which is having some text_field.
Refer this image for Popover.
So after entering value in all fields I have to do search and fire query and populate table view present in Search view controller. So when clicking on search I am calling that full_text_search function which use to fire query and populate data in table view. So in popover controller creating instance of search controller and calling search function but it is showing thread exception.
func full_text_search(){
self.view.endEditing(true)
image_contain.removeAll()
datafiles.removeAll()
search_table.reloadData()
search_table.delegate = self
search_table.dataSource = self
let defaults = UserDefaults.standard
let username = defaults.string(forKey: "username")
let password = defaults.string(forKey: "password")
var check_icon_flag = 0
let loginData = String(format: "%#:%#", username!, password!).data(using: String.Encoding.utf8)!
let base64LoginData = loginData.base64EncodedString()
let serarchbar_text = search_text.text
print(serarchbar_text)
var new_String = "http://xx.xxxx.com:9090/dtm-rest/repositories/xxx/search?q='"
new_String.append(serarchbar_text!+"'&object-type=dm_document")
let again_new_String = new_String.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
let url = URL(string: again_new_String!)
print(again_new_String)
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginData)", forHTTPHeaderField: "Authorization")
##After this use to fetch query result and at last i use refresh table data
So in above code it use to show thread exception in
search_table.reloadData
search_table.delegate = self
search_table.dataSource = self
If I call this function from search controller it is working fine. This function is defined in search controller only.But calling from popover controller it is giving exception.Below function shows calling full_text_search function from popover view controller.
#IBAction func Search(_ sender: Any) {
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
print("2sec")
let check_search = SearchViewController()
check_search.full_text_search()
}
removeAnimate()
}
What to do if I want to add some values to query using popover view and then do search.
How I am calling popover :
#IBAction func advance_search(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "types_popover") as! TypesViewController
self.addChildViewController(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParentViewController: self)
}

instead of populating the tableView from another VC, use delegates to populate it in its own VC, read more about delegates
Here
so inside the popover VC, you pass the parameters you required for search and fire up a function inside the tableview VC, and perform the searching pretty simple
in your case the delegate protocol function should hold all the required search parameters

Related

Navigation controller and remembering values

I have 2 view controller with navigation controller. First view controller has 4 text field and second view controller has 4 text field. To navigate first view controller to second I am using following code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var destinationVC:UIViewController
destinationVC = storyboard.instantiateViewController(withIdentifier: "SecondVC") as! SecondVC
navigationController?.show(destinationVC, sender: self)
To first from second view controller I am using
navigationController?.popViewController(animated: true)
However, even if the fields I have filled in first view controller keep the values when I go from first to second values I have written have disappear because of popviewcontroller method. What is the best way to remember values in second view controller?
You can have singleton where you can store the values as dictionary(or something else)
class Settings: NSObject {
static let shared = Settings()
public var dictionaryToStore: [String: String]?
private init() {
super.init()
}
}
And in your controller when poping
Settings.shared.dictionaryToStore = {"key1": textfield1.text, "key2": textfield2.text, ...
}
And in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
textfield1.text = Settings.shared.dictionaryToStore["key1"]
textfield2.text = Settings.shared.dictionaryToStore["key2"]
...
}
Also you can create custom object and store it.
EDIT 1 **
To have variables after app has been terminated you can save dictionary in UserDefaults
class Settings: NSObject {
static let shared = Settings()
public var dictionaryToStore: [String: String]? {
set(newValue) {
let defaults = UserDefaults.standard
defaults.set(newValue, forKey: "SomeKey")
}
get {
let defaults = UserDefaults.standard
let loadedValue = defaults.object(forKey: "SomeKey")
return loadedKey
}
}
private init() {
super.init()
}
}
The key reason for values not to be remembered on the SecondVC is that you're using new instances of SecondVC each time you open it.
So you better create an instance (first 3 lines of your code do that job) of SecondVC once, somewhere in the beginning of FirstVC, and use it in show() func everytime you need to show SecondVC instead of creating multiple instance of SecondVC each time.
In that case you'll see all values "remembered" in the SecondVC.
You can use key-value storage like NSUserDefaults in your secondViewController to save data when viewController will disappear and load on viewDidLoad. Or save your data in some struct/object instance and pass it when you push secondViewController.
if you want to pass data from you first view controller to second view
how to pass data from first viewcontroller to second viewcontroller
in above code though you are making new instance of you view controller still you can pass data by setting variable of second view controller in first view controller before
navigationController?.show(destinationVC, sender: self)
like
destnationVC.variableTOSet = valueTopass
and then
navigationController?.show(destinationVC, sender: self)
and then in second view controller use that variable to use value
so that how you can pass data from your first controller to second view controller
now if you want to pass data from your second viewController to first controller then you can use delegates

Change order in Navigation Controller

I'm working with Swift3. I have an App with the VCs as in the picture.
In the Mainmenu-VC the user triggers the Input-segue. User enters a firstname in the Input-VC. This triggers the Select-segue to Select-VC to select a surname and trigger Selected-segue to Details-VC.
From the Mainmenu-VC the user can also access the Details-VC. Back via NavigationControllerMechanism to Mainmenu-VC.
I want to change the NavigationControllerMechanism 'history', so that when the user enters from the Details-VC via the Selected-segue, the previous VC is changed from Select-VC to Mainmenu-VC.
So basically when in the Details-VC, the Back always returns to Mainmenu-VC.
I have tried combining various solutions from the web, without succes.
Is this possible?
Yes it is.
The View-Controller stack is stored in currentViewController.navigationController?.viewControllers.
So you should make something like :
//In Your Details VC :
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let stack = self.navigationController?.viewControllers else { return }
//get the mainMenu VC
let mainVC = stack.first!
// Rearrange your stack
self.navigationController?.viewControllers = [mainVC, self]
//Now you can press "bac" to Main VC
}
you want to change navigation stack in this way you can manipulate
let myprofile = storyboard.instantiateViewController(withIdentifier: "Profile1ViewController") as! Profile1ViewController
let sourseStack = self.navigationController!.viewControllers[0];
var controllerStack = self.navigationController?.viewControllers
let index = controllerStack!.index(of: sourseStack);
controllerStack![index!] = myprofile
self.navigationController!.setViewControllers(controllerStack!, animated: false);
to go to RootViewController
dispatch_async(dispatch_get_main_queue(), {
self.navigationController?.popToRootViewControllerAnimated(true)
})

IOS Swift how can I reload a tableView from a different controller

I have 2 controllers A and Controller B . Controller A has a TableView and Controller B is a subview that when clicked opens a form and on Submit it enters data into the database. My problem is that I attempt to reload my TableView from Controller B from the user hits submit and I get the following error
fatal error: unexpectedly found nil while unwrapping an Optional value from this line
self.TableSource.reloadData()
Now the data from Controller B is successfully inserted so after I restart my app the data I submit is there . This is my code (TableSource is the TableView outlet)
Controller A
func reloadTable(latmin: Float,latmax: Float,lonmin: Float, lonmax: Float) {
let url:URL = URL(string:ConnectionString+"MY-URL")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let parameter = "parameters"
request.httpBody = parameter.data(using: String.Encoding.utf8)
session.dataTask(with:request, completionHandler: {(data, response, error) in
if error != nil {
} else {
do {
let parsed = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
if let S = parsedData["myData"] as? [AnyObject] {
for A in Data {
// gets Json Data
}
DispatchQueue.main.async {
// This is what I named my TableView
self.TableSource.reloadData()
}
}
} catch let error as NSError {
print(error)
}
}
}).resume()
}
That is my HTTP-Request that gets data from the database, now in that same Controller A I have a button that when clicked opens the SubView to Controller B and this is the code
#IBAction func Post_Action(_ sender: Any) {
let Popup = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ControllerB") as! Controller B
self.addChildViewController(Popup)
Popup.view.frame = self.view.frame
self.view.addSubview(Popup.view)
Popup.didMove(toParentViewController: self)
}
This is the code in Controller B and this is how I try to reload the TableView in Controller A
#IBAction func Submit_Form(_ sender: Any) {
// Code that submits the form no issues here
latmin = 32.18
latmax = 32.50
lonmin = -81.12
lonmax = -81.90
let Homepage = ControllerA()
Homepage.reloadTable(latmin: latmin!,latmax: latmax!,lonmin: lonmin!,lonmax: lonmax!)
}
So as stated before Controller A loads the data from the Database, Controller B has a form and when submitted it enters new data into the database . That whole process works I just now want to update the TableView in Controller A from the form is submitted in Controller B
I would suggest using protocol:
protocol SomeActionDelegate {
func didSomeAction()
}
In ViewController B
var delegate: SomeActionDelegate?
In ViewController A when segue
viewControllerB.delegate = self
You should add this
extension ViewControllerA: SomeActionDelegate {
func didSomeAction() {
self.tableView.reloadData()
}
}
And in ViewController B
func didChangeSomething() {
self.delegate?.didSomeAction()
}
It works like when ViewController B didChangeSomething() it sends message to ViewController A that it should didSomeAction()
You can do it with NSNotification
in swift 3.0
Think you have two viwe controllers called viewcontrollerA and viewControllerB
viewcontrollerA has the tableview.
you need to reload it from viewcontrolerB
implementaion of viewcontrollerA
create a function to relod your tableview in viewcontrollerA and call it in viewDidLoad
override func viewDidLoad() {
let notificationNme = NSNotification.Name("NotificationIdf")
NotificationCenter.default.addObserver(self, selector: #selector(YourControllername.reloadTableview), name: notificationNme, object: nil)
}
func relodaTableview() {
self.TableSource.reloadData()
}
implementation in viewcontrollerB (where you want to reload tableview)
post the notification in button click or anywhere you want like below
let notificationNme = NSNotification.Name("NotificationIdf")
NotificationCenter.default.post(name: notificationNme, object: nil)
hope this will help to you.

Passing data between two view controllers are not working

I am trying to pass some data between two view controllers, but it doesn't work..
This is the data i am trying to pass(these has items from parse.com - the same code is in both view controllers):
var userFile = [PFFile]()
var createdAt = [NSDate]()
var objID = [String]()
This is the button for open the view controller(inside the first view controller i am trying to send data FROM):
#IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
}
The view controller is a ModalViewController.xib connected to ViewStoryModalViewController.swift
This is the viewDidLoad in the view controller i am trying to send data TO:
override func viewDidLoad() {
super.viewDidLoad()
print("USERFILECOUNT: \(self.userFile.count)")
}
My problem is that this is the messages i get in xCode output:
What might be wrong here? Any suggestions?
xCode output tells that an array self.userFile contains zero elements, It doesn't mean that it is passed wrong. It is just empty.
print("USERFILECOUNT: \(self.userFile.count)")
Check if it is empty before passing it to modal vc.
Try this code
You first need to present after that try to set variable.
IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
}

How to update managed object data?

I have started my first core data application. I am working with one entity right now called 'Folder'.
The first view controller displays all the Folders in a tableview, which I can add to and it reloads the data. This works fine because It uses the fetch request to populate the table.
override func viewWillAppear(animated: Bool) {
var error: NSError?
let request = NSFetchRequest(entityName: "Folder")
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
self.events = moc?.executeFetchRequest(request, error: &error) as! [Folder]
self.UITable.reloadData()
}
However when segueing to another view controller via the table cell I pass on the selected Folder data to the controller using the index path. e.g.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showDetails" {
let destinationVC = segue.destinationViewController as! FolderDetailsViewController
let indexPath = UITable.indexPathForSelectedRow()
let selectedFolder = folders[indexPath!.row]
destinationVC.selectedFolder = selectedFolder
}
}
My second view controller uses the data passed from the first table view to display in textfields:
var selectedFolder: Folder!
folderNameLabel.text = selectedFolder?.title
folderDetailsLabel.text = selectedFolder?.details
folderDateLabel.text = displayDate
I then have a modal to edit/save the folder data in a modal appearing from the second controller:
//Edit and save event
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
//Error
var error: NSError?
//Storing Data from fields
SelectedFolder!.title = FolderName.text
SelectedFolder!.details = FolderDetails.text
SelectedFolder!.date = FolderDate.date
context?.save(&error)
self.dismissViewControllerAnimated(true, completion: {});
When dismissing the modulate data is not updated, I have to go back to the first controller to reload the data and segue again.
I think this is because I have no NSFetchRequest (or NSFetchResultsController) to get the most recent changes.
What is the best method to reload the data of the selectedFolder when I make the changes in the modal ?
You can refresh your second view in viewWillAppera() if your modal view is presented in full screen.
override func viewWillAppear(animated: Bool) {
{
folderNameLabel.text = selectedFolder?.title
folderDetailsLabel.text = selectedFolder?.details
folderDateLabel.text = displayDate
}
It seems like you would want to call moc.refreshObject(folder, mergeChanges:true)
See the documentation here.

Resources