iOS Swift fetching more data for collection view after having navigated to detail view not working -
i working on assignment job interview. have finished of assignment. there's bug can't figure out. have been trying 3 days now.
i had make client app flickr api allows users search photos using specific words. display results in collection view infinite scroll. , when photo selected should show details of photo in detail view.
the bug: working if stay in collection view. can search on , on again , infinite scroll working.as specific index in index path hit. new request sent same search term. if select photo , navigate collection view , try new search nothing comes , error handeling returns error. (the error not console error).also when navigating detail collection. can still scroll until index triggers new request throws error.
i hope explaining well. getting desperate @ moment. tried think of: request url still works when try in browser.
please help! if need more info ask.
collection view controller:
import uikit // global variable holding search term. var searchterm: string? // global variable hold instance of reachability. var reachability: reachability? // enum changing textfield placeholder text. enum textfieldplaceholdertext: string { case search = "search" case searching = "searching..." } class photosviewcontroller: uiviewcontroller { // mark: - outlets @iboutlet var collectionview: uicollectionview! @iboutlet var searchtextfield: uitextfield! // mark: - properties let photodatasource = photodatasource() let photostore = photostore() // mark: - view setup override func viewdidload() { super.viewdidload() // sets data source , delegate. collectionview.datasource = photodatasource collectionview.delegate = self // uses image add pattern collection view background. collectionview.backgroundcolor = uicolor(patternimage: uiimage(named: "flickr.png")!) } override func viewwillappear(animated: bool) { super.viewwillappear(animated) // checks if device connected internet. checkforreachability() } // mark: showalert func showalert(title: string, message: string) { let alert = uialertcontroller(title: title, message: message, preferredstyle: .alert) let okaction = uialertaction(title: "ok", style: .cancel, handler: { (nil) in self.dismissviewcontrolleranimated(true, completion: nil) }) alert.addaction(okaction) self.presentviewcontroller(alert, animated: true, completion: nil) } // mark: - segue override func prepareforsegue(segue: uistoryboardsegue, sender: anyobject?) { if segue.identifier == "showphoto" { if let selectedindexpath = collectionview.indexpathsforselecteditems()?.first { let flickrphoto = photodatasource.flickrphotos[selectedindexpath.row] let destinationvc = segue.destinationviewcontroller as! photodetailviewcontroller destinationvc.flickrphoto = flickrphoto destinationvc.photostore = photostore } } } // mark: - checkforreachability func checkforreachability() { { reachability = try reachability.reachabilityforinternetconnection() } catch { print("unable create reachability") return } reachability!.whenreachable = { reachability in // called on background thread, ui updates must on main thread. nsoperationqueue.mainqueue().addoperationwithblock({ if reachability.isreachableviawifi() { print("reachable via wifi") } else { print("reachable via cellular") } }) } reachability!.whenunreachable = { reachability in // called on background thread, ui updates must on main thread. nsoperationqueue.mainqueue().addoperationwithblock({ print("not reachable") self.showalert("no internet connection", message: "make sure device connected internet.") }) } { try reachability!.startnotifier() } catch { print("unable start notifier") } } } //mark: - extension uicollectionviewdelegate extension photosviewcontroller: uicollectionviewdelegate { //mark: - willdisplaycell func collectionview(collectionview: uicollectionview, willdisplaycell cell: uicollectionviewcell, foritematindexpath indexpath: nsindexpath) { let flickrphoto = photodatasource.flickrphotos[indexpath.row] // downloads image data thumbnail. photostore.fetchimageforphoto(flickrphoto,thumbnail: true) { (result) -> void in // calls mainthread update ui. nsoperationqueue.mainqueue().addoperationwithblock() { // indexpath photo might have changed between time request started , finished, find recent indeaxpath let photoindex = self.photodatasource.flickrphotos.indexof(flickrphoto)! let photoindexpath = nsindexpath(forrow: photoindex, insection: 0) // when request finishes, update cell if it's still visible if let cell = collectionview.cellforitematindexpath(photoindexpath) as? photocollectionviewcell { cell.updatewithimage(flickrphoto.image) } } } } } //mark: - extension uitextfielddelegate extension photosviewcontroller : uitextfielddelegate { func textfieldshouldreturn(textfield: uitextfield) -> bool { // checks if textfield not empty. if textfield.text!.isempty { self.showalert("s😉rry", message: "no search term detected, please enter search term.") return false } else { let activityindicator = uiactivityindicatorview(activityindicatorstyle: .gray) textfield.addsubview(activityindicator) activityindicator.frame = textfield.bounds activityindicator.startanimating() textfield.placeholder = textfieldplaceholdertext.searching.rawvalue // sets text user typed value searchterm property. searchterm = textfield.text! // fetches photos flickr using user's search term. photostore.fetchphotosforsearchterm() { (photosresult) -> void in // calls mainthread update ui. nsoperationqueue.mainqueue().addoperationwithblock() { switch photosresult { case let .success(photos): // checks if photos found using search term. if photos.count == 0 { self.showalert("s😞rry", message: "no images found matching search for: \(searchterm!), please try again.") } activityindicator.removefromsuperview() textfield.placeholder = textfieldplaceholdertext.search.rawvalue // sets result data source array. self.photodatasource.flickrphotos = photos print("successfully found \(photos.count) recent photos.") case let .failure(error): self.checkforreachability() activityindicator.removefromsuperview() textfield.placeholder = textfieldplaceholdertext.search.rawvalue self.photodatasource.flickrphotos.removeall() self.showalert("", message: "something went wrong, please try again.") print("error fetching photo's search term: \(searchterm!), error: \(error)") } self.collectionview.reloadsections(nsindexset(index: 0)) } } textfield.text = nil textfield.resignfirstresponder() self.collectionview?.backgroundcolor = uicolor.whitecolor() return true } } } the detail view controller:
import uikit import social class photodetailviewcontroller: uiviewcontroller { // mark: - outlets @iboutlet var phototitlelabel: uilabel! @iboutlet var photoidlabel: uilabel! @iboutlet var datetakenlabel: uilabel! @iboutlet var imageview: uiimageview! // mark: properties var flickrphoto: flickrphoto! var photostore: photostore! let formatter = flickrapi.dateformatter // mark: - view setup override func viewdidload() { super.viewdidload() //downloads image data large image photostore.fetchimageforphoto(flickrphoto, thumbnail: false) { (result) -> void in switch result { case let .success(image): // calls mainthread update ui. nsoperationqueue.mainqueue().addoperationwithblock() { self.imageview.image = image } case let .failure(error): print(" error fetching detail image photo: \(error)") } } // formats date shorte date doesn't display time formatter.datestyle = .mediumstyle formatter.timestyle = .nostyle } override func viewwillappear(animated: bool) { super.viewwillappear(animated) // checks if device connected internet. checkforreachability() // configures ui. configureview() } // mark: - checkforreachability func checkforreachability() { { reachability = try reachability.reachabilityforinternetconnection() } catch { print("unable create reachability") return } reachability!.whenreachable = { reachability in // called on background thread, ui updates must on main thread, this: nsoperationqueue.mainqueue().addoperationwithblock({ if reachability.isreachableviawifi() { print("reachable via wifi") } else { print("reachable via cellular") } }) } reachability!.whenunreachable = { reachability in // called on background thread, ui updates must on main thread, this: nsoperationqueue.mainqueue().addoperationwithblock({ print("not reachable") self.showalert("no internet connection", message: "make sure device connected internet.") }) } { try reachability!.startnotifier() } catch { print("unable start notifier") } } // mark: - configureview func configureview() { phototitlelabel.text = flickrphoto.title ?? "no title available" photoidlabel.text = flickrphoto.photoid ?? "id unknown" datetakenlabel.text = formatter.stringfromdate(flickrphoto.datetaken) ?? " date unknown" } // mark: - showshareoptions @ibaction func showshareoptions(sender: anyobject) { // configure action sheet show sharing options. let actionsheet = uialertcontroller(title: "share photo", message: "", preferredstyle: uialertcontrollerstyle.actionsheet) let tweetaction = uialertaction(title: "share on twitter", style: uialertactionstyle.default) { (action) -> void in // check if sharing twitter possible. if slcomposeviewcontroller.isavailableforservicetype(slservicetypetwitter) { let twittercomposevc = slcomposeviewcontroller(forservicetype: slservicetypetwitter) twittercomposevc.addimage(self.imageview.image) self.presentviewcontroller(twittercomposevc, animated: true, completion: nil) } else { self.showalert("flickr searcher", message: "you not logged in twitter account.") } } // configure new action share on facebook. let facebookpostaction = uialertaction(title: "share on facebook", style: uialertactionstyle.default) { (action) -> void in if slcomposeviewcontroller.isavailableforservicetype(slservicetypetwitter) { let facebookcomposevc = slcomposeviewcontroller(forservicetype: slservicetypefacebook) facebookcomposevc.addimage(self.imageview.image) self.presentviewcontroller(facebookcomposevc, animated: true, completion: nil) } else { self.showalert("flickr searcher", message: "you not logged in facebook account.") } } // configure new action show uiactivityviewcontroller let moreaction = uialertaction(title: "more", style: uialertactionstyle.default) { (action) -> void in let activityviewcontroller = uiactivityviewcontroller(activityitems: [self.imageview.image!], applicationactivities: nil) self.presentviewcontroller(activityviewcontroller, animated: true, completion: nil) } let dismissaction = uialertaction(title: "cancel", style: uialertactionstyle.destructive) { (action) -> void in } actionsheet.addaction(tweetaction) actionsheet.addaction(facebookpostaction) actionsheet.addaction(moreaction) actionsheet.addaction(dismissaction) presentviewcontroller(actionsheet, animated: true, completion: nil) } // mark: showalert func showalert(title: string, message: string) { let alert = uialertcontroller(title: title, message: message, preferredstyle: .alert) let okaction = uialertaction(title: "ok", style: .cancel, handler: { (nil) in self.dismissviewcontrolleranimated(true, completion: nil) }) alert.addaction(okaction) self.presentviewcontroller(alert, animated: true, completion: nil) } } my data source:
import uikit class photodatasource: nsobject, uicollectionviewdatasource { //mark: - properties // array store flickr photos var flickrphotos = [flickrphoto]() // instance of photostore. var photostore = photostore() // mark: - numberofitemsinsection func collectionview(collectionview: uicollectionview, numberofitemsinsection section: int) -> int { return flickrphotos.count } // mark: - cellforitematindexpath func collectionview(collectionview: uicollectionview, cellforitematindexpath indexpath: nsindexpath) -> uicollectionviewcell { let identifier = "flickrcell" let cell = collectionview.dequeuereusablecellwithreuseidentifier(identifier, forindexpath: indexpath) as! photocollectionviewcell let photo = flickrphotos[indexpath.item] cell.updatewithimage(photo.image) print(indexpath.item) // if close end of collection, fetch more photo's. if indexpath.item == flickrphotos.count - 20 { print("detected end of collection") // fetch next batch of photos. photostore.fetchphotosforsearchterm() { (photosresult) -> void in // calls mainthread update ui. nsoperationqueue.mainqueue().addoperationwithblock() { switch photosresult { case let .success(photos): print("successfully found \(photos.count) recent photos.") self.flickrphotos.appendcontentsof(photos) case let .failure(error): self.flickrphotos.removeall() print("error fetching more photos search term \(error)") } collectionview.reloadsections(nsindexset(index: 0)) } } } return cell } } this method throws error. when navigated detail view first. staying in collection view method gets call on , on no problem:
photostore.fetchphotosforsearchterm() { (photosresult) -> void in // calls mainthread update ui. nsoperationqueue.mainqueue().addoperationwithblock() { switch photosresult { case let .success(photos): print("successfully found \(photos.count) recent photos.") self.flickrphotos.appendcontentsof(photos) case let .failure(error): self.flickrphotos.removeall() print("error fetching more photos search term \(error)") } collectionview.reloadsections(nsindexset(index: 0)) } }
Comments
Post a Comment