I have an app with a tab bar controller embedded in a navigation controller. The app has 2 tabs, the first one(search) has a search bar implemented using the UISearchController. If I switch from this tab to the other tab(downloads) while I'm searching, to the other tab two things happen -
The navigation bar in the second tab(downloads) disappears
When i come back to the first tab(search), it shows a black screen
I have done all this using the storyboard.
this is my SearchViewController
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate{
//MARK: Variables
var papers = [Paper]()
var filteredPapers = [Paper]()
let searchController = UISearchController(searchResultsController: nil)
// MARK: Outlets
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet var table: UITableView!
#IBOutlet weak var loadingMessageLabel: UILabel!
#IBOutlet weak var retryButton: UIButton!
//MARK: Actions
#IBAction func retryButton(sender: UIButton) {
self.loadingMessageLabel.hidden = false
self.loadingMessageLabel.text = "While the satellite moves into position..."
self.activityIndicator.hidden = false
self.activityIndicator.startAnimating()
self.retryButton.hidden = true
self.getPapersData()
}
// MARK: Table View
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If in searching mode, then return the number of results else return the total number
// if searchController.active && searchController.searchBar.text != "" {
if searchController.active {
return filteredPapers.count
}
return papers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let paper: Paper
// if searchController.active && searchController.searchBar.text != "" {
if searchController.active {
paper = filteredPapers[indexPath.row]
} else {
paper = papers[indexPath.row]
}
if let cell = self.table.dequeueReusableCellWithIdentifier("Cell") as? PapersTableCell {
cell.initCell(paper.name, detail: paper.detail)
print(cell)
return cell
}
return PapersTableCell()
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let downloadButton = UITableViewRowAction(style: .Normal, title: "Download") { action, index in
var url = String(self.papers[indexPath.row].url)
url = url.stringByReplacingOccurrencesOfString(" ", withString: "%20")
print(url)
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
// Spinner in cell
// var selectCell = self.table.cellForRowAtIndexPath(indexPath) as? PapersTableCell
// selectCell!.downloadSpinner.hidden = false
// Dismiss the download button
self.table.editing = false
Alamofire.download(.GET, url, destination: destination).response { _, _, _, error in
if let error = error {
print("Failed with error: \(error)")
} else {
print("Downloaded file successfully")
}
// selectCell?.downloadSpinner.hidden = true
}
}
downloadButton.backgroundColor = UIColor(red:0.30, green:0.85, blue:0.39, alpha:1.0)
return [downloadButton]
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// the cells you would like the actions to appear needs to be editable
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// you need to implement this method too or you can't swipe to display the actions
}
// MARK: Search
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredPapers = papers.filter { paper in
let categoryMatch = (scope == "All") || (paper.exam == scope)
return categoryMatch && paper.name.lowercaseString.containsString(searchText.lowercaseString)
}
table.reloadData()
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
// MARK: Defaults
override func viewDidLoad() {
super.viewDidLoad()
self.getPapersData()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
table.tableHeaderView = searchController.searchBar
searchController.searchBar.scopeButtonTitles = ["All", "ST1", "ST2", "PUT", "UT"]
searchController.searchBar.delegate = self
activityIndicator.startAnimating()
}
override func viewWillDisappear(animated: Bool) {
// if searchController.active {
self.searchController.resignFirstResponder()
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: API call
func getPapersData(){
Alamofire.request(.GET, "http://silive.in/bytepad/rest/api/paper/getallpapers?query=")
.responseJSON { response in
self.activityIndicator.stopAnimating()
self.activityIndicator.hidden = true
// If the network works fine
if response.result.isFailure != true {
self.loadingMessageLabel.hidden = true
self.table.hidden = false
//print(response.result) // result of response serialization
let json = JSON(response.result.value!)
for item in json {
// Split the title on the . to remove the extention
let title = item.1["Title"].string!.characters.split(".").map(String.init)[0]
let category = item.1["ExamCategory"].string
let url = item.1["URL"].string
let detail = item.1["PaperCategory"].string
let paper = Paper(name: title, exam: category!, url: url!, detail: detail!)
self.papers.append(paper)
}
self.table.reloadData()
}
// If the network fails
else {
self.retryButton.hidden = false
self.loadingMessageLabel.text = "Check your internet connectivity"
}
}
}
}
And this is my DownloadViewController
import UIKit
import QuickLook
class DownloadViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, QLPreviewControllerDataSource {
var items = [(name:String, url:String)]()
#IBOutlet weak var downloadsTable: UITableView!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(items[indexPath.row].url)
// performSegueWithIdentifier("DocumentViewSegue", sender: items[indexPath.row].url)
let previewQL = QLPreviewController() // 4
previewQL.dataSource = self // 5
previewQL.currentPreviewItemIndex = indexPath.row // 6
showViewController(previewQL, sender: nil) // 7
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = self.downloadsTable.dequeueReusableCellWithIdentifier("Download Cell") as? DownloadsTableCell {
cell.initCell(items[indexPath.row].name, detail: "", fileURL: items[indexPath.row].url)
return cell
}
return DownloadsTableCell()
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
// let fileManager = NSFileManager.defaultManager()
//
// // Delete 'hello.swift' file
//
// do {
// try fileManager.removeItemAtPath(String(items[indexPath.row].url))
// }
// catch let error as NSError {
// print("Ooops! Something went wrong: \(error)")
// }
items.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
override func viewDidAppear(animated: Bool) {
items.removeAll()
let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
// now lets get the directory contents (including folders)
do {
let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
// print(directoryContents)
for var file in directoryContents {
print(file.lastPathComponent)
print(file.absoluteURL)
// Save the data in the list as a tuple
self.items.append((file.lastPathComponent!, file.absoluteString))
}
} catch let error as NSError {
print(error.localizedDescription)
}
downloadsTable.reloadData()
}
// MARK: Preview
func numberOfPreviewItemsInPreviewController(controller: QLPreviewController) -> Int {
return items.count
}
func previewController(controller: QLPreviewController, previewItemAtIndex index: Int) -> QLPreviewItem {
return NSURL(string: items[index].url)!
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
//do something
super.viewWillAppear(true)
}
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.
}
*/
}
Looks like the view that your UISearchController is attached to gets removed from the view hierarchy. You can think of the UISearchController as being presented modally when you start searching, and the definesPresentationContext property indicates which UIViewController would be the one to present it (more on this).
One of the ways to fix this would be reconfiguring your storyboard so that each tab has its own UINavigationController (in case you need it for both):
Instead of (what I suspect you have now):
And if you want to dismiss UISearchController when the tab switches, add this override to the ViewController:
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
searchController.active = false
}
Related
I got my data from a json url, but when I want to load my images, it is very slowly !
class NewsTableViewController: UITableViewController {
var ids = [String]()
var titles = [String]()
var descriptions = [String]()
var images = [String]()
var links = [String]()
var dates = [String]()
#IBOutlet var table_news: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table_news.delegate = self
getNews()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.ids.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:NewsTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "news_cell") as! NewsTableViewCell
cell.lbl_date.text = self.dates[indexPath.row]
cell.lbl_title.text = self.titles[indexPath.row]
var des = self.descriptions[indexPath.row]
if des.characters.count > 200 {
let range = des.rangeOfComposedCharacterSequences(for: des.startIndex..<des.index(des.startIndex, offsetBy: 200))
let tmpValue = des.substring(with: range).appending("...")
cell.lbl_des.text = tmpValue
}
DispatchQueue.main.async{
cell.img_news.setImageFromURl(stringImageUrl: self.images[indexPath.row])
}
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func getNews() {
RestApiManager.sharedInstance.getNews { (json: JSON) in
if let results = json.array {
for entry in results {
self.ids.append(entry["id"].string!)
self.titles.append(entry["title"].string!)
self.descriptions.append(entry["description"].string!)
self.images.append(entry["images"].string!)
self.links.append(entry["link"].string!)
self.dates.append(entry["date"].string!)
}
DispatchQueue.main.async{
self.table_news.reloadData()
}
}
}
}
}
custom cell:
extension UIImageView{
func setImageFromURl(stringImageUrl url: String){
if let url = NSURL(string: url) {
if let data = NSData(contentsOf: url as URL) {
self.image = UIImage(data: data as Data)
}
}
}
}
class NewsTableViewCell: UITableViewCell {
#IBOutlet weak var img_news: UIImageView!
#IBOutlet weak var lbl_title: UILabel!
#IBOutlet weak var lbl_date: UILabel!
#IBOutlet weak var lbl_des: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
lbl_des.lineBreakMode = .byWordWrapping // or NSLineBreakMode.ByWordWrapping
lbl_des.numberOfLines = 0
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
I'm using an extension image view.
The problem for the slowness you are mentioning are in the UIImageView extension
extension UIImageView{
func setImageFromURl(stringImageUrl url: String){
if let url = NSURL(string: url) {
if let data = NSData(contentsOf: url as URL) {
self.image = UIImage(data: data as Data)
}
}
}
}
In the NSData(contentsOf: url as URL) you are retrieving the contents of the URL synchronously from the network, blocking the main thread. You can download the content using a NSURLSession with an asynchronous callback or using some 3rd party libraries (SDWebImage probably being the most used and battle tested).
I am using realm for my notepad app to store the array noteTitles, which is of a custom class Note. The app works fine, but when it is supposed to save, it doesn't pass through. When I restart the app, the notes are gone. I will give code to all of the files. Also, I want the user to add notes and I need the ObjectForPrimaryKey to update everytime so a new id is created for each note.
Note Class Code:
import Foundation
import RealmSwift
class Note: Object {
dynamic var title = ""
var content = ""
var id = 0
override class func primaryKey() -> String? {
print("id generated")
return "id"
}
}
ViewController(Where I write the notes) Code:
import UIKit
import RealmSwift
var note2 = Note()
var note: Note!
let realm = try! Realm()
class ViewController3: UIViewController, UITextViewDelegate {
var note: Note!
#IBOutlet var noteText: UITextView!
#IBOutlet var noteTitle: UITextField!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
noteTitle.text = note.title
noteText.text = note.content
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
note.title = noteTitle.text!
note.content = noteText.text
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textViewDidEndEditing(textView: UITextView) {
func noteEnded(note2: Note) {
note2.title = note.title
note2.content = note.content
note2.id = note.id
do {
try realm.write {
realm.add(noteTitles, update: true)
print("added")
}
} catch {
print("There was a problem")
}
}
print("editing ended")
}
override func viewDidLoad() {
super.viewDidLoad()
print(note2.id)
self.noteText.delegate = self
// Do any additional setup after loading the view.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
noteTitle.resignFirstResponder()
noteText.resignFirstResponder()
}
}
TableViewController(Note List) Code:
import UIKit
import RealmSwift
var noteTitles:[Note] = []
class TableViewController: UITableViewController {
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return noteTitles.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = noteTitles[indexPath.row].title // error here
// Configure the cell...
return cell
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
sleep(2)
if realm.objectForPrimaryKey(Note.self, key: 0) != nil {
realm.objectForPrimaryKey(Note.self, key: 0)
}
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
noteTitles.removeAtIndex(indexPath.row)
tableView.reloadData()
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier! == "editNote" {
let noteDetailViewController = segue.destinationViewController as! ViewController3
let selectedIndexPath = tableView.indexPathForSelectedRow
noteDetailViewController.note = noteTitles[selectedIndexPath!.row]
} else if segue.identifier! == "addNote" {
let note = Note()
noteTitles.append(note)
let noteDetailViewController = segue.destinationViewController as! ViewController3
noteDetailViewController.note = note
}
}
}
Thanks in advance!
The function noteEnded should not inside the textViewDidEndEditing and it is not being called.
Try this
func noteEnded(note2: Note) {
do {
try realm.write {
realm.add(note2, update: true)
print("added")
}
} catch {
print("There was a problem")
}
}
func textViewDidEndEditing(textView: UITextView) {
note2.title = note.title
note2.content = note.content
note2.id = note.id
noteEnded(note2)
print("editing ended")
}
It is also better to have "Done" button to save the note. Easy to handle the input and save.
Working on an IOS app(swift 1.2, Xcode 6.3), I'm implementing the UISearchController in a ViewController and I'm getting an error in the data source method (cellForRowAtIndexPath) when I try return a cell for a table view, becouse I don't know to obtain an indexpath.row from a dictionary. The error is Cannot subscript a value of type [String : AnyObject] with an index of type Int and the code of the view controller is:
import Foundation
import UIKit
class UsersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableview:UITableView!
let apiClient = ApiClient()
var users: [User]!
var searchArray:[AnyObject] = [AnyObject](){
didSet {self.tableview.reloadData()}
}
var usersSearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
self.usersSearchController = ({
// Two setups provided below:
// Setup One: This setup present the results in the current view.
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.searchBarStyle = .Minimal
controller.searchBar.sizeToFit()
self.tableview.tableHeaderView = controller.searchBar
return controller
})()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
println("UsersController viewWillAppear")
apiClient.usersService.getList() { users, error in
if users != nil {
self.users = users
self.tableview?.reloadData()
} else {
println("error: \(error)")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if ( self.usersSearchController.active){
return self.searchArray.count ?? 0
} else {
return self.users?.count ?? 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("userObjectCell") as! UserTableViewCell
if (self.usersSearchController.active){
cell.userObject = self.searchArray[indexPath.row] as? User//HERE IS THE ERROR
return cell
} else {
cell.userObject = self.users?[indexPath.row]
return cell
}
}
}
extension UsersViewController: UITableViewDelegate
{
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
extension UsersViewController: UISearchResultsUpdating
{
func updateSearchResultsForSearchController(searchController: UISearchController)
{
// self.searchArray.removeAll(keepCapacity: false)
//
// let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
// let array = (self.users as NSArray).filteredArrayUsingPredicate(searchPredicate)
// self.searchArray = array as! [String: AnyObject]
}
}
Dictionaries don't have indexes, they have keys. You may want to consider a method of parsing your dictionary data and putting it into an ordered list, like an Array, so your data will appear in the same place. (Dictionaries are not ordered).
I can fetch the image from a url and able to display the image in a UIImageView in my DetailViewController. I would like to display the same image from this URL as a thumbnail in my tableviewcell.
My viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.UrlField.text = contact.Imageurl
let urlString = UrlField.text
loadImageView(urlString)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
let urlString = UrlField.text
loadImageView(urlString)
textField.resignFirstResponder()
return true
}
In this function I try to fetch the image from the URL
func loadImageView(url : String){
self.contact.Imageurl = url
self.contact.data = nil
let DatatoImage: (NSData?) -> Void = {
if let d = $0 {
let image = UIImage(data: d)
self.imageView.image = image
}else{
self.imageView.image = nil
}
}
if let d = contact.data {
DatatoImage(d)
} else {
contact.loadImage(DatatoImage)
}
}
In my cellForRowAtIndexPath I managed to load an image that I have hardcoded in my folder and named it as "images1.jpeg"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
MainViewController
import UIKit
class MasterTableViewController: UITableViewController, ContactDetailTableViewControllerDelegate {
var contacts: [ContactListEntry] = []
var currentContact: ContactListEntry!
var detailObject: ContactDetailTableViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
#IBAction func addContact(sender: UIBarButtonItem) {
currentContact = ContactListEntry(firstName: "", lastName: "", address: "", Imageurl: "")
contacts.append(currentContact)
performSegueWithIdentifier("showDetail", sender: self)
}
/* override func viewWillAppear(animated: Bool) {
if self.currentContact == nil || self.currentContact.isEmpty()
{
if count(contacts) > 0
{
contacts.removeLast()
}
}
tableView.reloadData()
}*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
/*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 contacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("contactcell", forIndexPath: indexPath) as! UITableViewCell
let contact = contacts[indexPath.row]
cell.textLabel?.text = "\(contact.firstName) \(contact.lastName)"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
let url = NSURL(string: "<# place your URL here #>")
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
*/
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// 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.
}
*/
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let cell = sender as? UITableViewCell
{
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
if (segue.identifier == "showDetail")
{
if let dvc = segue.destinationViewController as? ContactDetailTableViewController{
let indexPath = tableView.indexPathForCell(cell)!
currentContact = contacts[indexPath.row]
dvc.contact = currentContact
}}}
if let dvc = segue.destinationViewController as? ContactDetailTableViewController
{
dvc.contact = currentContact
dvc.delegate = self
}
}
func masterViewController(dvc: ContactDetailTableViewController, didUpdate contact: Person)
{
dvc.contact = currentContact
dvc.delegate = self
dvc.dismissViewControllerAnimated(true, completion: nil)
navigationController?.popToViewController(self, animated: true)
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
}
/* Create our configuration first In view did load */
let configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15.0
configuration.URLCache=NSURLCache(memoryCapacity: 4*1024*1024, diskCapacity: 20*1024*1024, diskPath: "CustomName"))
configuration.requestCachePolicy=NSURLRequestUseProtocolCachePolicy;
/* Now create our session which will allow us to create the tasks */
var session: NSURLSession!
session = NSURLSession(configuration: configuration,
delegate: self,
delegateQueue: nil)
/* Now attempt to download the contents of the URL in tableView cellForRowAtIndexpath */
let url = NSURL(string: "<# place your URL here #>")
task=session.dataTaskWithRequest(url!, completionHandler: { (NSData!, NSURLResponse!, NSError!) -> Void in
cell.imageView.image=UIImage(data: NSData))
})
task.start()
You can also set the cache,so that next tym when the request is fired then it is called from cache
When I go to my secondViewController using
let secondViewController:SecondViewController = SecondViewController()
self.presentViewController(secondViewController, animated: true, completion: nil)
I know I can send varibles to SECOND ONE using secondViewController.theNum = num, but while secondViewController is presented how to send varibles bar to the original ViewController.
Thing is I would like to start viewdidload() on original ViewController after this part of code is finished
self.dismissViewControllerAnimated(true, completion:nil)
Here are the full classes for two Views from a project where I pass data to a detail view and use a protocol/delegate method to return data to the first view:
View 1:
import UIKit
class Contacts: UITableViewController, dataUpdated {
//Declaring contact structure
struct contactInfo {
var name: String
var phoneNumber: String
}
var listOfContacts: [contactInfo] = []
var Duration = 100
//Sample contacts
var firstContact = contactInfo(name: "John Coffey" , phoneNumber: "(111) 111-1111")
var secondContact = contactInfo(name: "Cathy Kane" , phoneNumber: "(222) 222-2222")
//TableView delegates
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfContacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("contact", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = listOfContacts[indexPath.row].name
cell.detailTextLabel?.text = listOfContacts[indexPath.row].phoneNumber
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
listOfContacts.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
//ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem()
listOfContacts.append(firstContact)
listOfContacts.append(secondContact)
}
//Passing details to detail VC
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ToDetail" {
let indexPath = self.tableView.indexPathForSelectedRow()
let theSelectedRow = listOfContacts[indexPath!.row]
let theDestination = (segue.destinationViewController as ContactDetails)
theDestination.contactName = theSelectedRow.name
theDestination.contactPhone = theSelectedRow.phoneNumber
} else if segue.identifier == "ToInput" {
(segue.destinationViewController as ContactInput).delegate = self
}
}
override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
let fromContact = listOfContacts[sourceIndexPath.row]
listOfContacts.removeAtIndex(sourceIndexPath.row)
listOfContacts.insert(fromContact, atIndex: destinationIndexPath.row)
}
//Delegate method to update the array with new contact
func didUpdateContact(senderClass: AnyObject, aName: String, aPhoneNumber: String) {
var newContact = contactInfo(name: aName, phoneNumber: aPhoneNumber)
listOfContacts.append(newContact)
println(listOfContacts)
self.tableView.reloadData()
}
}
View2:
import UIKit
protocol dataUpdated:NSObjectProtocol {
func didUpdateContact(senderClass: AnyObject, aName: String, aPhoneNumber: String)
}
class ContactInput: UIViewController, UITextFieldDelegate {
//Properties
var name = ""
var phoneNumber = ""
var delegate: dataUpdated?
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var phoneField: UITextField!
//Textfield delegates
func textFieldShouldReturn(textField: UITextField!) -> Bool {
if textField.tag == 1 {
self.name = textField.text
}
else {
self.phoneNumber = textField.text
}
textField.resignFirstResponder()
return true
}
//Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.nameField.delegate = self
self.phoneField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if name != "" && phoneNumber != "" {
self.delegate!.didUpdateContact(self, aName: self.name, aPhoneNumber: self.phoneNumber)
}
}
}