iphone - crash in resignFirstResponder in uitableview -


in uitableview have set of custom cells contain uitextfield. found out (the hard way), apparently leaving current view (either pushing new view controller or dismissing active view ('go back')) make app crash, when keypad still visible.

to hide keypad when user still editing uitextfield, view changed, added [self.view endediting:yes]; before push new view controller, , in viewwilldisappear method.

now, app crashing 1 out of 5 trys hide keypad. here learned reason this: when cell moved offscreen, destroyed/recycled, can dequeued again when needed. means, once cell , contained textfields moves off screen, sending resignfirstresponder message (either manually or [self.view endediting:yes];, app crash. backtrace:

#0  0x012e309b in objc_msgsend () #1  0x05956888 in dyld_stub_usleep () #2  0x003ff056 in -[uiresponder resignfirstresponder] () #3  0x003c697f in -[uitextfield resignfirstresponder] () #4  0x003c6ab1 in -[uiview(uitextfield) endediting:] () #5  0x00012c0a in -[mycontroller viewwilldisappear:] (self=0x7419e90, _cmd=0x52aa27e, animated=1 '\001') @ mycontroller:121 #6  0x003ee9a2 in -[uinavigationcontroller _starttransition:fromviewcontroller:toviewcontroller:] () #7  0x003e932a in -[uinavigationcontroller _startdeferredtransitionifneeded] () #8  0x003e8fb6 in -[uinavigationcontroller _popviewcontrollerwithtransition:allowpoppinglast:] () #9  0x003e9142 in -[uinavigationcontroller popviewcontrolleranimated:] () #10 0x003e857a in -[uinavigationcontroller navigationbar:shouldpopitem:] () #11 0x00389260 in -[uinavigationbar _popnavigationitemwithtransition:] () #12 0x0039261b in -[uinavigationbar _handlemouseupatpoint:] () #13 0x00354ded in -[uiwindow _sendtouchesforevent:] () #14 0x00335c37 in -[uiapplication sendevent:] () #15 0x0033af2e in _uiapplicationhandleevent () #16 0x01ad5992 in purpleeventcallback () #17 0x0115e944 in __cfrunloop_is_calling_out_to_a_source1_perform_function__ () #18 0x010becf7 in __cfrunloopdosource1 () #19 0x010bbf83 in __cfrunlooprun () #20 0x010bb840 in cfrunlooprunspecific () #21 0x010bb761 in cfrunloopruninmode () #22 0x01ad41c4 in gseventrunmodal () #23 0x01ad4289 in gseventrun () #24 0x0033ec93 in uiapplicationmain () #25 0x00001e18 in main (argc=1, argv=0xbffff0a0) @ main.m:24 

my question is, how correctly hide keypad of uitextfield inside uitableviewcell in situations? (table view disappears, new view controller pushed, cell/textfield moved off screen, etc.)

any highly appreciated, can't rid of crashes!

ill include more code:

1) custom cell class:

#import <uikit/uikit.h>  enum type {    tptext = 0,    tpinteger,    tpdecimal,    tpnumber };  @protocol textinputcelldelegate <nsobject> @required - (void)setnewtext:(nsstring*)newtext forindex:(nsindexpath*)index; @end  @interface textinputcell : uitableviewcell <uitextfielddelegate> {    iboutlet uilabel* maintext;    iboutlet uitextfield* textfield;    nsnumberformatter* numberformatter;    int type;    id <textinputcelldelegate> delegate; }  - (void) initdelegatewithtype:(int)atype; - (void) save:(nsstring*)text; - (void) startediting;  @property (nonatomic, retain) uilabel* maintext; @property (nonatomic, retain) uitextfield* textfield; @property (nonatomic, retain) nsnumberformatter* numberformatter; @property (nonatomic, assign) int type; @property (nonatomic, assign) id <textinputcelldelegate> delegate;  @end 

implementation of custom cell:

#import "textinputcell.h"  @implementation textinputcell  @synthesize maintext; @synthesize textfield; @synthesize numberformatter; @synthesize type; @synthesize delegate;  - (void) initdelegatewithtype:(int)atype {    self.type = atype;    textfield.delegate = self;    }   - (bool)textfield:(uitextfield *)atextfield shouldchangecharactersinrange:(nsrange)range replacementstring:(nsstring *)string; {     if (![string length] || type == tptext || (isnumber([string characteratindex:0]) && type == tpnumber))    {       [self save:[textfield.text stringbyreplacingcharactersinrange:range withstring:string]];        return yes;    }     char c = [string characteratindex:0];     bool issep = [string isequaltostring:[numberformatter decimalseparator]];    bool isminus = [string isequaltostring:@"-"];    nsrange sep;    sep.location = nsnotfound;    sep.length = 0;     if ([atextfield.text length])       sep = [atextfield.text rangeofstring:[numberformatter decimalseparator]];     if (isminus)    {       // allow '-' if type tpnumber , field empty        if (type != tpnumber)          return no;        if ([atextfield.text length])          return no;        [self save:[textfield.text stringbyreplacingcharactersinrange:range withstring:string]];       return yes;    }     if (isnumber(c) || ((type == tpdecimal || type == tpnumber) && issep && sep.location == nsnotfound))    {       // allow separator decimal , number, if not in text        if (!issep && sep.location != nsnotfound && type == tpdecimal)       {          // round after , (only decimal type)           nsstring* text = [nsstring stringwithformat:@"%@%@", atextfield.text, string];          double num = [[numberformatter numberfromstring:text] doublevalue];          double res = ((int)(num / 0.5)) * 0.5;          atextfield.text = [numberformatter stringfromnumber:[nsnumber numberwithdouble:res]];           [self save:atextfield.text];           return no;       }        [self save:[nsstring stringwithformat:@"%@%@", atextfield.text, string]];        return yes;    }     [self save:[nsstring stringwithformat:@"%@%@", atextfield.text, string]];     return no; }  - (void) save:(nsstring*)text {     uitableview* view = (uitableview*)[self superview];    nsindexpath* index =  [view indexpathforcell:self];     if (delegate)       [delegate setnewtext:text forindex:index]; }  - (bool)textfieldshouldendediting:(uitextfield *)field  {    nslog(@"should end");  //   if ([field becomefirstresponder]) //      [field resignfirstresponder];     return yes; }  - (bool)textfieldshouldreturn:(uitextfield *)field {     if (type != tptext && [field.text length] == 0)       field.text = @"0";     nslog(@"should return");  //   if ([field becomefirstresponder]) //      [field resignfirstresponder];     return yes; }  - (void) startediting {     nslog(@"should return");     [self.textfield becomefirstresponder]; }  @end 

view controller contains 4 of cells:

@implementation mailprefcontroller  @synthesize menuitems; @synthesize mailto; @synthesize mailcc; @synthesize mailbcc; @synthesize mailsubject; @synthesize mailbody;   #pragma mark - #pragma mark initialization   - (id)initwithstyle:(uitableviewstyle)style {     // override initwithstyle: if create controller programmatically , want perform customization not appropriate viewdidload.     if ((self = [super initwithstyle:uitableviewstylegrouped])) {     }     return self; }   #pragma mark - #pragma mark view lifecycle   - (void)viewdidload {     [super viewdidload];     // save button     uibarbuttonitem* savebutton = [[uibarbuttonitem alloc] initwithbarbuttonsystemitem:uibarbuttonsystemitemsave target:self action:@selector(savemailprefs)];    self.navigationitem.rightbarbuttonitem = savebutton;    [savebutton release];     self.navigationitem.title = nslocalizedstring(@"mail template", nil);     // menu items     self.menuitems = [[nsarray alloc] initwithobjects:nslocalizedstring(@"to:", nil), nslocalizedstring(@"cc:", nil), nslocalizedstring(@"bcc:", nil), nslocalizedstring(@"subject:", nil), nslocalizedstring(@"body:", nil), nil]; }   - (void)viewwilldisappear:(bool)animated {     [super viewwilldisappear:animated]; }  #pragma mark - #pragma mark table view data source  - (nsinteger)numberofsectionsintableview:(uitableview *)tableview {     // return number of sections.     return 1; }   - (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section {     // return number of rows in section.     return [menuitems count]; }   // customize appearance of table view cells. - (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath {     if (indexpath.row < 4)    {       // title        textinputcell* textcell = (textinputcell*)[tableview dequeuereusablecellwithidentifier:@"textinputcell"];        if (textcell == nil)       {          nsarray* nibcontents = [[nsbundle mainbundle] loadnibnamed:@"textinputcell" owner:self options:nil];          textcell = [nibcontents lastobject];           textcell.selectionstyle = uitableviewcellselectionstylenone;          textcell.textfield.textcolor = [service uicolor];          textcell.delegate = self;          [textcell initdelegatewithtype:tptext];       }        textcell.maintext.text = [menuitems objectatindex:indexpath.row];        switch (indexpath.row)       {          case 0: textcell.textfield.text = self.mailto; break;          case 1: textcell.textfield.text = self.mailcc; break;          case 2: textcell.textfield.text = self.mailbcc; break;          case 3: textcell.textfield.text = self.mailsubject; break;           default: break;       }        return textcell;    }     // body text multiline     textinputmultilinecell* textmultilinecell = (textinputmultilinecell*)[tableview dequeuereusablecellwithidentifier:@"textinputmultilinecell"];     if (textmultilinecell == nil)    {       nsarray* nibcontents = [[nsbundle mainbundle] loadnibnamed:@"textinputmultilinecell" owner:self options:nil];       textmultilinecell = [nibcontents lastobject];        textmultilinecell.selectionstyle = uitableviewcellselectionstylenone;       textmultilinecell.textview.font = [uifont systemfontofsize:12];       textmultilinecell.textview.textcolor = [service uicolor];       textmultilinecell.delegate = self;       [textmultilinecell initdelegate];        cgrect rect = textmultilinecell.textview.frame;       rect.size.height *= 2;       textmultilinecell.textview.frame = rect;    }     textmultilinecell.maintext.text = [menuitems objectatindex:indexpath.row];    textmultilinecell.textview.text = self.mailbody;     return textmultilinecell; }  - (void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath {     switch (indexpath.section)    {       case 0:       {          // general section           if (indexpath.row < 4)          {             textinputcell* cell = (textinputcell*)[[self tableview] cellforrowatindexpath:indexpath];                         [cell startediting];          }       }        default: break;    } } 

the crash can reproduced clicking 1 of cells uitextfield, slide cell off screen (without hiding keypad), dismissing tableview (e.g. go via navigation controller).

could caused manually opening keypad when cell clicked? (startediting method) user not have hit textfield, editing starts when e.g. taps cells textlabel.

maybe bit late, had similar problem. see zombies enabled uitextview trying messaged (with textviewdidendediting) after deallocation scrolling out of view. in dealloc of equivalent of textinputcell, set uitextfield delegate nil. worked treat.


Comments

Popular posts from this blog

c++ - Is it possible to compile a VST on linux? -

java - Output of Eclipse is rubbish -

jquery - Confused with JSON data and normal data in Django ajax request -