Everyone, I'm having difficulties finding documentation on how to implement a Search filter for My Movie DB app ill attach my code so far below I've managed to get the data to show up in the table view
The title and Image What I need to do now is being able to filter the movies with a search bar then when clicking on a row it goes to a new View controller displaying expanded information about the movie then a button to "bookmark" save it to core data then appear on a bookmark screen for the user to view later.
Thanks in Advance
My code is here:
import UIKit
import AFNetworking
class ViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate, UISearchBarDelegate {
var movies: [NSDictionary]?
#IBOutlet weak var txtSearch: UITextField!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
// Do any additional setup after loading the view, typically from a nib.
fetchMovies()
searchBar()
}
func searchBar(){
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width:
self.view.frame.width, height: 50))
searchBar.delegate = self
searchBar.showsScopeBar = true
searchBar.tintColor = UIColor.lightGray
searchBar.scopeButtonTitles = ["Now Playing"]
self.tableView.tableHeaderView = searchBar
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
if searchText == ""{
fetchMovies()
}else{
if searchBar.selectedScopeButtonIndex == 0 {
movies = movies?.filter({ (movies) -> Bool in
return movies.title.lowercased()
})
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return movies?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MovieTableViewCell
let movie = movies![indexPath.row]
let title = movie["title"] as! String
let posterPath = movie["poster_path"] as! String
let baseUrl = "https://image.tmdb.org/t/p/w300/"
let imageUrl = NSURL(string: baseUrl + posterPath)
cell.lblTitle.text = title
cell.imgMovie.setImageWith(imageUrl! as URL)
print("row \(indexPath.row)")
return cell
}
func fetchMovies(){
let apiKey = "2c0a8efe934c162f5535ff33303e70bd"
let url = NSURL(string: "https://api.themoviedb.org/3/movie/now_playing?api_key=\(apiKey)")
let request = URLRequest(url: url! as URL, cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 10)
let session = URLSession(
configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: OperationQueue.main
)
let task: URLSessionDataTask = session.dataTask(with: request, completionHandler:{(dataOrNil, repsonse, error) in
if let data = dataOrNil {
if let responseDictionary = try! JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary{print("response: \(responseDictionary)")
self.movies = responseDictionary["results"] as? [NSDictionary]
self.tableView.reloadData()
}
}
})
task.resume()
}
#IBAction func btnBookmark(_ sender: UIButton) {
}
}
Related
I am trying to filter the data from API. The is successful loaded into view controller with table view cell . This is a movie applications . I am trying to filter the data based on the user type into the text box . I mentioned in the code filter my the title of the movie but The code is only able to filter the title and overview of the movie but the Image fields remain unfiltered such as image , overview etc. Here is the struct model .
import Foundation
struct Movie: Decodable {
let originalTitle: String
let overview: String
let posterPath: String
enum CodingKeys: String, CodingKey {
case originalTitle = "original_title"
case overview
case posterPath = "poster_path"
}
}
Here is the protocol class code .
import Foundation
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
var movies = [Movie]()
private var cache = [Int: Data]()
var rows: Int {
return movies.count
}
init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
self.view = view
self.networkManager = networkManager
}
func getMovies() {
let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
networkManager.getMovies(from: url) { [weak self] result in
switch result {
case .success(let response):
self?.movies = response.results
self?.downloadImages()
DispatchQueue.main.async {
self?.view.resfreshTableView()
}
case .failure(let error):
DispatchQueue.main.async {
self?.view.displayError(error.localizedDescription)
}
}
}
}
func getTitle(by row: Int) -> String? {
return movies[row].originalTitle
}
func getOverview(by row: Int) -> String? {
return movies[row].overview
}
func getImageData(by row: Int) -> Data? {
return cache[row]
}
private func downloadImages() {
let baseImageURL = "https://image.tmdb.org/t/p/w500"
let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
let group = DispatchGroup()
group.enter()
for (index, url) in posterArray.enumerated() {
networkManager.getImageData(from: url) { [weak self] data in
if let data = data {
self?.cache[index] = data
}
}
}
group.leave()
group.notify(queue: .main) { [weak self] in
self?.view.resfreshTableView()
}
}
}
Here is the controller code .
import UIKit
class MovieViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
private var presenter: MoviePresenter!
var finalname = ""
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
presenter = MoviePresenter(view: self)
searchBarText()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
private func searchBarText() {
searchBar.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 1{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == ""{
presenter.getMovies()
}
else {
presenter.movies = presenter.movies.filter({ movies in
return movies.originalTitle.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
dc.imagemovie = UIImage(data: presenter.getImageData(by: row)!)
self.navigationController?.pushViewController(dc, animated: true)
}
}
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Here is the screenshot of the result .
Caching image in tableview is a little bit tricky, and you may get problem when the cell changes or reusing itself,
that's cause you see same image when texts are different.
there are 2 famous package you can use it for you're problem and it's easy to use with a lot of options.
1- Kingfisher
2- SDWebImage
Ok so, I am trying to make a custom table that has a news feed from newsapi, from my debugging: the api calls and such get made and the data is acessed, its just that it doesnt display on the table, it shows up as a blank table.
Here is the code:
This is from the "first view controller" as I am using the tabbed template
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var articles: [Article]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchArticles()
}
func fetchArticles(){
let urlRequest = URLRequest(url: URL(string: "https://newsapi.org/v2/top-headlines?country=us&?category=business&apiKey=sorrynotgivingmykey")!)
let task = URLSession.shared.dataTask(with: urlRequest){(data,response,error) in
if error != nil{
print(error)
return
}
self.articles = [Article]()
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJson = json["articles"] as? [[String: AnyObject]]{
for articlesFromJson in articlesFromJson{
let article = Article()
if let title = articlesFromJson["title"] as? String, let desc = articlesFromJson["description"] as? String, let url = articlesFromJson["url"] as? String, let imageToUrl = articlesFromJson["urlToImage"] as? String, let date = articlesFromJson["publishedAt"] as? String{
article.headline = title
article.desc = desc
article.url = url
article.imageUrl = imageToUrl
article.date = date
// print(article.date)
// print(article.headline)
}
self.articles?.append(article)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch let error{
print(error)
}
}
task.resume()
// print(articles)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.articles!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "worklmao", for: indexPath) as! ArticleCell
cell.title.text = self.articles?[indexPath.item].headline
cell.desc.text = self.articles?[indexPath.item].desc
cell.date.text = self.articles?[indexPath.item].date
print("lol lmao hahax help fuck shit")
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
1
}
}
And this is the cell classes I used for the articles
import UIKit
class ArticleCell: UITableViewCell {
#IBOutlet weak var date: UILabel!
#IBOutlet weak var desc: UILabel!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var ImgView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
This is the article class
import UIKit
class Article: NSObject {
var headline: String?
var desc: String?
var url: String?
var date: String?
var imageUrl: String?
}
and bare in mind I did setup the class for the cell properly(at least I think
Still, this is what I get:
Don't forget to connect dataSource and delegate for tableView.
Change your tableView outlets to this:
#IBOutlet weak var tableView: UITableView! {
didSet {
tableView.delegate = self
tableView.dataSource = self
}
}
Some points:
You don't have to declare articles array as optional. Simply do this :
var articles = [Article]()
Try to learn about codables for JSON parsing.
I am trying to make a social media feed/ wall using the UITableView with custom cells (cells called PostTableViewCell.xib) I am using this through Firebase Database. Currently I have a view controller for the feed (called HomeViewController.swift) and a separate view controller for the user to post (called NewPostViewController.swift)
My problem is every time a user made a post it would show up at the very bottom of the table and not the top like instagram, twitter, facebook would do. I was able to get around this by flipping the UiTableView and its cells 180 degrees, but now it loads that home view controller at the bottom of all the posts but the cells are now in the right order.
How can I start this home page at the top of these cells while having new cells come in at the top too. Attached is the necesary code on that homeviewcontroller:
import Foundation
import UIKit
import Firebase
class HomeViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds, style: .plain)
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
tableView.backgroundColor = UIColor(white: 0.90,alpha:1.0)
view.addSubview(tableView)
var layoutGuide:UILayoutGuide!
if #available(iOS 11.0, *) {
layoutGuide = view.safeAreaLayoutGuide
} else {
// Fallback on earlier versions
layoutGuide = view.layoutMarginsGuide
}
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
observePosts()
//Flips UITableView
tableView.transform = CGAffineTransform(rotationAngle: (-.pi))
}
func observePosts() {
let postsRef = Database.database().reference().child("posts")
postsRef.observe(.value, with: { snapshot in
var tempPosts = [Post]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot,
let dict = childSnapshot.value as? [String:Any],
let author = dict["author"] as? [String:Any],
let uid = author["uid"] as? String,
let username = author["username"] as? String,
let photoURL = author["photoURL"] as? String,
let url = URL(string:photoURL),
let text = dict["text"] as? String,
let timestamp = dict["timestamp"] as? Double {
let userProfile = UserProfile(uid: uid, username: username, photoURL: url)
let post = Post(id: childSnapshot.key, author: userProfile, text: text, timestamp:timestamp)
tempPosts.append(post)
}
}
self.posts = tempPosts
self.tableView.reloadData()
})
}
#IBAction func handleLogout(_ sender:Any) {
try! Auth.auth().signOut()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.set(post: posts[indexPath.row])
//Flips cell
cell.transform = CGAffineTransform(rotationAngle: (-.pi))
return cell
}
}
The reason it is appearing at the bottom is because you are appending it here:
tempPosts.append(post)
Append puts the new element at the end of the array. You should be inserting it at the first position like so:
tempPosts.insert(post, at: 0)
Alternatively, you should be sorting the data that you are serving by the date created. Create a variable:
_posts: [Post] {
get {
return self.posts.sorted(by: { $0.timestamp > $1.timestamp } )
}
}
and then use your _posts variable.
I am building an app that uses the Twitter API to post to a user's Twitter and load those tweets in a TableView. The table loads correctly when the app first launches. However, after composing and posting a Tweet (confirmed that the Tweet is posted and in the array) the table view is still displaying the same tweets prior without the newly created one. I thought it might have something to do with the asynchronous code so I implemented the DispatchQueue in the refreshData() function. The table view is still not loading the most recently added tweet. How can I change the refreshData() function so that the table updates when Tweet is posted successfully?
import UIKit
import OAuthSwift
class FeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var tweetText: UITextField!
var user: User!
var tweets = [Tweet]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.rowHeight = 200
let consumerSecret = user.consumerSecret
let consumerKey = user.consumerKey
let oAuthToken = user.oAuthToken
let oAuthSecret = user.oAuthSecret
let oauthswift = user.oauthswift
let screen_name = user.screen_name
print("Feed Consumer Secret: \(consumerSecret)")
print("Feed Consumer Key: \(consumerKey)")
print("Feed Auth Token: \(oAuthToken)")
print("Feed Auth Secret: \(oAuthSecret)")
print("Screen Name: \(screen_name)")
loadFeed(oauthswift: oauthswift)
// Do any additional setup after loading the view.
}
#IBAction func postButtonPushed(_ sender: Any) {
let oauthswift = user.oauthswift
let url = "https://api.twitter.com/1.1/statuses/update.json?status="
let tweet_url = tweetText.text
let encoded_tweet = tweet_url?.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)
let new_url = url + encoded_tweet!
let _ = oauthswift.client.post(
new_url, parameters: [:],
success: { response in
let dataString = response.string!
let jsonDict = try? response.jsonObject()
let jsonDict2 = jsonDict as! Dictionary<String,Any>
let tweetText2 = jsonDict2["text"]!
let jsonDict4 = jsonDict2["user"] as! Dictionary<String,Any>
let username = jsonDict4["screen_name"]!
let newTweet = Tweet(tweetText: tweetText2 as! String, username: username as! String)
self.tweets.append(newTweet)
print(username)
//print(dataString)
self.loadFeed(oauthswift: oauthswift)
self.tweetText.text = ""
},
failure: { error in
print(error)
}
)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tweet = tweets[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell {
cell.configureCell(tweet: tweet)
return cell
} else {
return PostCell()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tweets.count
}
func loadFeed(oauthswift: OAuth1Swift){
print("LOAD FEED")
let _ = oauthswift.client.get(
"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=\(user.screen_name)", parameters: [:],
success: { response in
let jsonDict = try? response.jsonObject()
let jsonDict2 = jsonDict as! Array<Dictionary<String,Any>>
let arrayCount = jsonDict2.count
for index in 0...arrayCount - 1 {
let jsonDict4 = jsonDict2[index]["user"] as! Dictionary<String,Any>
let tweetText = jsonDict2[index]["text"]!
let username = jsonDict4["screen_name"]!
let newTweet = Tweet(tweetText: tweetText as! String, username: username as! String)
self.tweets.append(newTweet)
print(tweetText)
}
self.refreshData()
}, failure: { error in
print(error)
}
)
}
func refreshData() {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
}
PostCell.swift
import UIKit
class PostCell: UITableViewCell {
#IBOutlet weak var userLabel: UILabel!
#IBOutlet weak var tweetLabel: UILabel!
var tweet: Tweet!
func configureCell(tweet: Tweet) {
self.userLabel.text = "#\(tweet.username)"
self.tweetLabel.text = tweet.tweetText
print(tweet.tweetText)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Since you are sure that Twitter accepted the post and you appended the new Tweet to the data source there is no need for a full reloadData. You can display just the new row in the table.
In FeedViewController, in method postButtonPushed, inside the oauthswift.client.post's success clousure right after this line self.tweets.append(newTweet) add this:
DispatchQueue.main.async {
self.tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath(item: self.tweets.count-1, section: 0)],
with: .automatic)
self.tableView.endUpdates()
}
I'm currently working on an inventory app that will hold information for two entities. The first entity holds two attributes "site name" and "site address". second entity holds "itemName" "itemQuantity" and "item picture". I'm able to save the data to core data. I'm having issues with fetching the data right now. Does any one know how to pass data between the view controllers.
I'm uploading the site view controller, detail view controller, and my new item view controller.
class SiteTableViewController: UIViewController {
var managedContext : NSManagedObjectContext = CoreDataHelper.sharedInstance.myContext
var sites : [Site]? = [Site]()
//variable to hold selected site
var selectedSite : Site?
let myCellIdentifier = "cell"
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
sites = [Site]()
reloadData()
automaticallyAdjustsScrollViewInsets = false
//let barButtonItem = UIBarButtonItem(barButtonSystemItem: .Compose, target: self, action: "addSite:")
//self.navigationItem.leftBarButtonItems = [barButtonItem]
}
//load new data into table
func reloadData() {
let fetchRequest = NSFetchRequest(entityName: "Site")
let sortDescriptor = NSSortDescriptor(key: "siteName", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
sites = try self.managedContext.executeFetchRequest(fetchRequest) as! [Site]
tableView.reloadData()
} catch {
print("Error fetching objects")
}
tableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
reloadData()
}
}
extension SiteTableViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(myCellIdentifier, forIndexPath: indexPath)
let site = sites![indexPath.row]
cell.textLabel?.text = site.valueForKey("siteName") as? String
cell.detailTextLabel?.text = site.valueForKey("siteAddress") as? String
return cell
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let logItemToDelete = sites![indexPath.row]
sites?.removeAtIndex(indexPath.row)
managedContext.deleteObject(logItemToDelete)
do {
try managedContext.save()
} catch {
print("Could not save or delete object")
}
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sites!.count
}
// func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//
// selectedSite = sites![indexPath.row]
//
// }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailSegue" {
var nextVC = segue.destinationViewController as! DetailTableViewController
var selectedItem : Site = sites![self.tableView.indexPathForSelectedRow!.row] as Site
fetchSite = selectedItem.valueForKey("siteName") as? NSManagedObject
nextVC.valueToPass = selectedItem.siteName!
}
}
}
here is my detail view controller
import UIKit
import CoreData
public var fetchSite : NSManagedObject?
class DetailTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var holdSiteData: NSMutableArray = NSMutableArray()
var managedContext : NSManagedObjectContext = CoreDataHelper.sharedInstance.myContext
#IBOutlet weak var tableView: UITableView!
var sites : [Site]!
//string to hold fetchResults controll
//open string to hold siteName
var valueToPass = ""
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "\(valueToPass)"
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
automaticallyAdjustsScrollViewInsets = false
tableView.estimatedRowHeight = 75.0
tableView.rowHeight = UITableViewAutomaticDimension
retrieveItemRelationship()
}
override func viewWillAppear(animated: Bool) {
retrieveItemRelationship()
}
func retrieveItemRelationship() {
// fetchSite.setValue(NSSet(keyCommands), forKey: "test")
let fetchRequest = NSFetchRequest(entityName: "SiteItem")
let sortDescriptors = NSSortDescriptor(key: "itemName", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptors]
do {
let result = try fetchSite?.managedObjectContext?.executeRequest(fetchRequest)
} catch let error as NSError {
print(error)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
// let cellInfo = fetchedResultsController.objectAtIndexPath(indexPath) as! SiteInfo
cell.cellName?.text = "Test"
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return holdSiteData.count
}
}
this is my last view to save the data to. I figured i need to pass the data here then associate the two entities so that I can save it correctly. For instance, for site name "Staples Center". I need to pull this over to the final view controller then save the information to this object.
import UIKit
import CoreData
class ItemNewViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//var managedObjectContext : NSManagedObjectContext!
var managedContext : NSManagedObjectContext = CoreDataHelper.sharedInstance.myContext
//categories array for picker view
var categories = ["Building Materials", "Electrical", "Cleaning Products",
"Tools & Hardware", "Plumbing", "Paint", "Appliances", "Other"]
//textFields
#IBOutlet weak var itemNameTextField: UITextField!
#IBOutlet weak var quantityTextField: UITextField!
#IBOutlet weak var imageView: UIImageView!
//Label properties
#IBOutlet weak var newItemLabel: UILabel!
#IBOutlet weak var quantityLabel: UILabel!
#IBOutlet weak var categoryLabel: UILabel!
//pickerLabel
#IBOutlet weak var pickerListIcon: UIPickerView!
//clicker property label and textlabel for number
#IBOutlet weak var increaseNumberClicker: UIStepper!
#IBOutlet weak var numberFieldClicker: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//label property customize view code
newItemLabel.layer.masksToBounds = true
newItemLabel.layer.borderWidth = 2.0
newItemLabel.layer.borderColor = UIColor.whiteColor().CGColor
newItemLabel.layer.cornerRadius = 6
//label property customize view code
quantityLabel.layer.masksToBounds = true
quantityLabel.layer.borderWidth = 2.0
quantityLabel.layer.borderColor = UIColor.whiteColor().CGColor
quantityLabel.layer.cornerRadius = 6
//lable property customize view code
categoryLabel.layer.masksToBounds = true
categoryLabel.layer.borderWidth = 3.0
categoryLabel.layer.borderColor = UIColor.whiteColor().CGColor
categoryLabel.layer.cornerRadius = 6
//label picker customize view
pickerListIcon.layer.masksToBounds = true
pickerListIcon.layer.borderWidth = 3.0
pickerListIcon.layer.borderColor = UIColor.whiteColor().CGColor
pickerListIcon.layer.cornerRadius = 6
pickerListIcon.layer.backgroundColor = UIColor.blackColor().CGColor
self.pickerListIcon.dataSource = self
self.pickerListIcon.delegate = self
numberFieldClicker.enabled = false
//UIStepper value
increaseNumberClicker.wraps = true
increaseNumberClicker.autorepeat = true
increaseNumberClicker.layer.masksToBounds = true
increaseNumberClicker.layer.borderWidth = 3.0
increaseNumberClicker.layer.borderColor = UIColor.whiteColor().CGColor
increaseNumberClicker.layer.cornerRadius = 6
increaseNumberClicker.layer.backgroundColor = UIColor.blackColor().CGColor
//below code declares a variable that inherits from UITapGesture
//this allows the image view to be an action
//*Make sure you enable user interaction in storyBoard very IMPORTANT!
let imageTapRecognizer = UITapGestureRecognizer(target: self, action: "enableImage")
self.imageView.addGestureRecognizer(imageTapRecognizer)
}
// below function allows the camera view to be accessible
func enableImage(){
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
let cameraView = UIImagePickerController()
cameraView.sourceType = UIImagePickerControllerSourceType.Camera
cameraView.delegate = self
self.presentViewController(cameraView, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.imageView.image = image
picker.dismissViewControllerAnimated(true, completion: nil)
}
//function used to increase UIStepper. increment by integers of one
#IBAction func clickerIncreaser(sender: UIStepper) {
numberFieldClicker.text = Int(sender.value).description
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return categories.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return categories[row]
}
func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
//passing the categorories array into the new constant myCategoriesArray
let myCategoriesArray = categories[row]
let myTextColor = NSAttributedString(string: myCategoriesArray, attributes: [NSForegroundColorAttributeName: UIColor.whiteColor()])
return myTextColor
}
//save data to core data
#IBAction func saveButton(sender: AnyObject) {
if (itemNameTextField.text?.isEmpty)! {
let displayAlertController = UIAlertController(title: "Form Incomplete", message: "Please provide item with a name", preferredStyle: .Alert)
let okButton : UIAlertAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
displayAlertController.addAction(okButton)
self.presentViewController(displayAlertController, animated: true, completion: nil)
} else {
//declare site object and object
let siteInfoEntity = NSEntityDescription.entityForName("SiteItem", inManagedObjectContext: self.managedContext)
//declare item and item object
let siteObject = SiteItem(entity: siteInfoEntity!, insertIntoManagedObjectContext: self.managedContext)
//convert String to Integer
let quantityNumber: Int? = Int(quantityTextField.text!)
siteObject.setValue(itemNameTextField.text?.capitalizedString, forKey: "itemName")
siteObject.setValue(quantityNumber, forKey: "itemQnty")
fetchSite?.setValue(NSSet(object: siteObject), forKey: "reverseItems")
self.managedContext.saveOrLogError()
self.navigationController?.popViewControllerAnimated(true)
}
}
}
Once again if someone can point me in the right direction for saving my relationships to core data and retrieving these relationships would be great. Still new to core data so need all the help i can get!
Thank you
Your detail controller can have a property Site. In prepareForSegue you pass the selected Site object to the detail controller.
Both the site list and the list of items should be backed by NSFetchedResultsController, not in-memory arrays.