Thursday 15 April 2010

uitableview - SearchBar, Custom Cell and setCell method: fatal error: unexpectedly found nil while unwrapping an Optional value -



uitableview - SearchBar, Custom Cell and setCell method: fatal error: unexpectedly found nil while unwrapping an Optional value -

i implemented searchbar , searchdisplaycontroller on tableview (in masterviewcontroller). have customcell works fine displaying tableview's cells doesn't work search tableview's cells , dont' understand why.

here's customcell class:

import uikit class customcell: uitableviewcell { @iboutlet weak var pgrmlabel: uilabel! @iboutlet weak var notelabel: uilabel! @iboutlet weak var logoview: uiimageview! override func awakefromnib() { super.awakefromnib() // initialization code } override func setselected(selected: bool, animated: bool) { super.setselected(selected, animated: animated) // configure view selected state } func setcell(pgrmname:string, noteint:int, logoname:string){ println("setcell") if allow itemname=self.pgrmlabel{ itemname.text=pgrmname println("pgrmname: \(pgrmname)") } if allow itemnote=self.notelabel{ itemnote.text=string(noteint) } if allow itemlogo=self.logoview{ itemlogo.image=uiimage(named: logoname) } else{ println("setcell else") self.pgrmlabel.text=pgrmname string self.notelabel.text=string(noteint) self.logoview.image=uiimage(named: logoname string) } } }

and cellforrowatindexpath method in masterviewcontroller:

override func tableview(tableview: uitableview, cellforrowatindexpath indexpath: nsindexpath) -> uitableviewcell { var program:program var cell: customcell!=tableview.dequeuereusablecellwithidentifier("cell") customcell! if(cell==nil){ println("cell nil") tableview.registerclass(customcell.classforcoder(), forcellreuseidentifier: "cell") cell=customcell(style: uitableviewcellstyle.default, reuseidentifier: "cell") } else{ if tableview == searchdisplaycontroller?.searchresultstableview{ println("searchcell") program=filteredprograms[indexpath.row] } else{ println("mastercell") program=arrayofprograms[indexpath.row] } cell.setcell(program.name string, noteint: program.note, logoname: program.imagename string) } homecoming cell }

also, here's programme class:

import foundation class program{ var name:string var note:int var imagename:string var channel:string init(name:string, note:int, imagename:string, channel:string){ self.name=name self.note=note self.imagename=imagename self.channel=channel } }

the app crashes when type letter in searchbar in setcell method. prints:

cell nil searchcell setcell setcell else fatal error: unexpectedly found nil while unwrapping optional value

if knows what's happening, helpful.

thanks lot.

edit: doesn't crash have empty search tableview if alter setcell method this:

self.pgrmlabel?.text=pgrmname self.notelabel?.text=string(noteint) self.logoview?.image=uiimage(named: logoname)

the 3 parameters pgrmname, noteint , logoname not nil pgrmlabel, notelabel , logoview are. guess (because these optional values) don't assign values right way.

i did way: deleted cell tableview in mainstoryboard , created new file (with xib file) create custom cell.

here's code of custom class cell:

class tablecell: uitableviewcell { @iboutlet weak var pgrmlabel: uilabel! @iboutlet weak var notelabel: uilabel! @iboutlet weak var logoview: uiimageview! override func awakefromnib() { super.awakefromnib() // initialization code } override func setselected(selected: bool, animated: bool) { super.setselected(selected, animated: animated) // configure view selected state } func setcell(cell: tablecell, pgrmname:string, noteint:int, logoname:string){ if allow itemname=self.pgrmlabel{ itemname.text=pgrmname } if allow itemnote=self.notelabel{ itemnote.text="\(noteint)" } if allow itemlogo=self.logoview{ itemlogo.image=uiimage(named: logoname) if ((itemlogo.image) == nil){ itemlogo.image=uiimage(named: "placeholder.jpg") } } } }

i created basetableviewcontroller class, , masterviewcontroller (main tableview) , resultstableviewcontroller (which created) inherit it.

basetableviewcontroller:

class basetableviewcontroller: uitableviewcontroller { // mark: types struct constants { struct nib { static allow name = "tablecell" } struct tableviewcell { static allow identifier = "cellid" } } // mark: view life cycle override func viewdidload() { super.viewdidload() allow nib = uinib(nibname: constants.nib.name, bundle: nil) // required if our subclasses use: dequeuereusablecellwithidentifier:forindexpath: tableview.registernib(nib, forcellreuseidentifier: constants.tableviewcell.identifier) } // mark: func configurecell(cell: tablecell, forprogram program: program) { cell.setcell(cell, pgrmname: program.name, noteint: program.note, logoname: program.imagename) } override func tableview(tableview: uitableview, estimatedheightforrowatindexpath indexpath: nsindexpath) -> cgfloat { homecoming 100 } override func tableview(tableview: uitableview, heightforrowatindexpath indexpath: nsindexpath) -> cgfloat { homecoming 100 } }

masterviewcontroller:

class masterviewcontroller: basetableviewcontroller, uitableviewdatasource, uitableviewdelegate, uisearchbardelegate, uisearchdisplaydelegate, uisearchresultsupdating { struct restorationkeys { static allow viewcontrollertitle = "viewcontrollertitlekey" static allow searchcontrollerisactive = "searchcontrollerisactivekey" static allow searchbartext = "searchbartextkey" static allow searchbarisfirstresponder = "searchbarisfirstresponderkey" } //controllers var detailviewcontroller: detailviewcontroller? = nil var searchcontroller: uisearchcontroller! var resultstablecontroller: resultstableviewcontroller! var restoredstate=searchcontrollerrestorablestate() //array of programs display in tableview var arrayofprograms=[program]() struct searchcontrollerrestorablestate { var wasactive=false var wasfirstresponder=false } override func awakefromnib() { super.awakefromnib() if uidevice.currentdevice().userinterfaceidiom == .pad { self.clearsselectiononviewwillappear = false self.preferredcontentsize = cgsize(width: 320.0, height: 600.0) } } override func viewdidload() { super.viewdidload() //self.navigationitem.leftbarbuttonitem = self.editbuttonitem() if allow split = self.splitviewcontroller { allow controllers = split.viewcontrollers self.detailviewcontroller = controllers[controllers.count-1].topviewcontroller as? detailviewcontroller } self.setupprograms() allow tableviewcontroller=navigationcontroller?.viewcontrollers[0] masterviewcontroller resultstablecontroller=resultstableviewcontroller() resultstablecontroller.tableview.delegate=self searchcontroller=uisearchcontroller(searchresultscontroller: resultstablecontroller) searchcontroller.searchresultsupdater=self searchcontroller.searchbar.sizetofit() tableview.tableheaderview=searchcontroller.searchbar searchcontroller.delegate=self searchcontroller.dimsbackgroundduringpresentation=false searchcontroller.searchbar.delegate=self definespresentationcontext=true override func viewdidappear(animated: bool) { super.viewdidappear(animated) // restore searchcontroller's active state. if restoredstate.wasactive { searchcontroller.active = restoredstate.wasactive restoredstate.wasactive = false if restoredstate.wasfirstresponder { searchcontroller.searchbar.becomefirstresponder() restoredstate.wasfirstresponder = false } } } func searchbarsearchbuttonclicked(searchbar: uisearchbar) { searchbar.resignfirstresponder() } override func tableview(tableview: uitableview, didselectrowatindexpath indexpath: nsindexpath) { var selectedprogram:program if tableview == self.tableview { selectedprogram=arrayofprograms[indexpath.row] } else{ selectedprogram=resultstablecontroller.filteredprograms[indexpath.row] } allow detailviewcontroller=detailviewcontroller.forprogram(selectedprogram) navigationcontroller!.pushviewcontroller(detailviewcontroller, animated: true) tableview.deselectrowatindexpath(indexpath, animated: true) } // mark: - table view override func numberofsectionsintableview(tableview: uitableview) -> int { homecoming 1 } override func tableview(tableview: uitableview, numberofrowsinsection section: int) -> int { homecoming arrayofprograms.count } func updatesearchresultsforsearchcontroller(searchcontroller: uisearchcontroller) { allow searchresults=arrayofprograms // strip out leading , trailing spaces. allow whitespacecharacterset = nscharacterset.whitespacecharacterset() allow strippedstring = searchcontroller.searchbar.text.stringbytrimmingcharactersinset(whitespacecharacterset) allow searchitems = strippedstring.componentsseparatedbystring(" ") [string] // build "and" expressions each value in searchstring. var andmatchpredicates = [nspredicate]() searchstring in searchitems { // each searchstring creates or predicate for: name, yearintroduced, introprice. // // illustration if searchitems contains "iphone 599 2007": // name contains[c] "iphone" // name contains[c] "599", yearintroduced ==[c] 599, introprice ==[c] 599 // name contains[c] "2007", yearintroduced ==[c] 2007, introprice ==[c] 2007 // var searchitemspredicate = [nspredicate]() // name field matching. var lhs = nsexpression(forkeypath: "name") var rhs = nsexpression(forconstantvalue: searchstring) var finalpredicate = nscomparisonpredicate(leftexpression: lhs, rightexpression: rhs, modifier: .directpredicatemodifier, type: .containspredicateoperatortype, options: .caseinsensitivepredicateoption) searchitemspredicate.append(finalpredicate) // channel field matching. lhs = nsexpression(forkeypath: "channel") rhs = nsexpression(forconstantvalue: searchstring) finalpredicate = nscomparisonpredicate(leftexpression: lhs, rightexpression: rhs, modifier: .directpredicatemodifier, type: .containspredicateoperatortype, options: .caseinsensitivepredicateoption) searchitemspredicate.append(finalpredicate) // add together or predicate our master , predicate. allow ormatchpredicates = nscompoundpredicate.orpredicatewithsubpredicates(searchitemspredicate) andmatchpredicates.append(ormatchpredicates) } // match fields of product object. allow finalcompoundpredicate = nscompoundpredicate.andpredicatewithsubpredicates(andmatchpredicates) allow filteredresults = searchresults.filter { finalcompoundpredicate.evaluatewithobject($0) } // hand on filtered results our search results table. allow resultscontroller = searchcontroller.searchresultscontroller resultstableviewcontroller resultscontroller.filteredprograms = filteredresults resultscontroller.tableview.reloaddata() } override func tableview(tableview: uitableview, cellforrowatindexpath indexpath: nsindexpath) -> uitableviewcell { allow cell = tableview.dequeuereusablecellwithidentifier(constants.tableviewcell.identifier, forindexpath: indexpath) tablecell allow program=arrayofprograms[indexpath.row] configurecell(cell, forprogram: program) homecoming cell } override func tableview(tableview: uitableview, caneditrowatindexpath indexpath: nsindexpath) -> bool { // homecoming false if not want specified item editable. homecoming false } override func encoderestorablestatewithcoder(coder: nscoder) { super.encoderestorablestatewithcoder(coder) // encode title. coder.encodeobject(navigationitem.title!, forkey:restorationkeys.viewcontrollertitle) // encode search controller's active state. coder.encodebool(searchcontroller.active, forkey:restorationkeys.searchcontrollerisactive) // encode first responser status. coder.encodebool(searchcontroller.searchbar.isfirstresponder(), forkey:restorationkeys.searchbarisfirstresponder) // encode search bar text. coder.encodeobject(searchcontroller.searchbar.text, forkey:restorationkeys.searchbartext) } override func decoderestorablestatewithcoder(coder: nscoder) { super.decoderestorablestatewithcoder(coder) // restore title. if allow decodedtitle = coder.decodeobjectforkey(restorationkeys.viewcontrollertitle) as? string { title = decodedtitle } else { fatalerror("a title did not exist. in app, handle gracefully.") } // restore active state: // can't create searchcontroller active here since it's not part of view // hierarchy yet, instead in viewwillappear. // restoredstate.wasactive = coder.decodeboolforkey(restorationkeys.searchcontrollerisactive) // restore first responder status: // above, can't create searchcontroller first responder here since it's not part of view // hierarchy yet, instead in viewwillappear. // restoredstate.wasfirstresponder = coder.decodeboolforkey(restorationkeys.searchbarisfirstresponder) // restore text in search field. searchcontroller.searchbar.text = coder.decodeobjectforkey(restorationkeys.searchbartext) string } }

resultstableviewcontroller

class resultstableviewcontroller: basetableviewcontroller { var filteredprograms=[program]() override func viewdidload() { super.viewdidload() println("results table view") } override func didreceivememorywarning() { super.didreceivememorywarning() // dispose of resources can recreated. } override func tableview(tableview: uitableview, numberofrowsinsection section: int) -> int { println("results table view nb of raws in section") homecoming filteredprograms.count } override func tableview(tableview: uitableview, cellforrowatindexpath indexpath: nsindexpath) -> uitableviewcell { //let cell=tableview.dequeuereusablecellwithidentifier(constants.tableviewcell.identifier) tablecell! allow cell = tableview.dequeuereusablecellwithidentifier(constants.tableviewcell.identifier, forindexpath: indexpath) tablecell allow programme = filteredprograms[indexpath.row] configurecell(cell, forprogram: program) homecoming cell } }

uitableview swift uisearchbar custom-cell uisearchbardisplaycontrol

No comments:

Post a Comment