UIRefresh Control title gets misaligned after couple of refreshes [duplicate] - ios

The text is offset wrong by the first launch of UIRefreshControl... later sometimes the refresh text doesn't show up at all and just the spiny is visible
I don't think i had this issue with iOS6... might be related to iOS7
Is in a UITableViewController added as a child to a VC, which resides in a modal presented UINavigationController
- (void)viewDidLoad {
[super viewDidLoad];
[self setRefreshControlText:#"Getting registration data"];
[self.refreshControl beginRefreshing];
}
- (void)setRefreshControlText:(NSString *)text {
UIFont * font = [UIFont fontWithName:#"Helvetica-Light" size:10.0];
NSDictionary *attributes = #{NSFontAttributeName:font, NSForegroundColorAttributeName : [UIColor blackColor]};
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attributes];
}

This is definitely an iOS 7 bug, but I haven't figured out exactly what caused it. It appears to have something to do with the view hierarchy — adding my UITableViewController as a child view to a wrapper view controller appeared to fix it for me at first, although the bug is back since iOS 7 GM.
It looks like adding the following code to your UITableViewController after creating the refresh view fixes the positioning issue for good:
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl beginRefreshing];
[self.refreshControl endRefreshing];
});

calling endRefreshing under viewWillAppear did it for me:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.refreshControl endRefreshing];
}
Under iOS7 with a custom UITableViewController inside a UINavigationController

I had the same problem and for me it worked with layoutIfNeeded after setting the attributedTitle:
- (void)setRefreshControlText:(NSString *)text
{
UIColor *fg = [UIColor colorWithWhite:0.4 alpha:1.0];
NSDictionary *attrsDictionary = #{NSForegroundColorAttributeName: fg};
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attrsDictionary];
[self.refreshControl layoutIfNeeded];
}
Cédric suggested to use [self.refreshControl setNeedsLayout], but this does not force an immediate update of the view, so you must use layoutIfNeeded.

I finally found the holy grail on this, which looks working in all cases
note : UIRefreshControl is added to a UITableViewController (note, never add UIRefreshControl just as subview to a normal UIVIewController's UITableView) (best to add UITableViewController as a child VC inside a UIViewController if you must)
note : that this also fixes the problem, that the UIRefreshControl is not vissible at first refresh (link)
Add to you .h
#interface MyViewController ()
#property (nonatomic, assign) BOOL refreshControlFixApplied;
- (void)beginRefreshing;
- (void)beginRefreshingWithText:(NSString *)text;
- (void)endRefreshing;
- (void)endRefreshingWithText:(NSString *)text;
#end
Add to you .m
////////////////////////////////////////////////////////////////////////
#pragma mark - UIRefreshControl Fix (peter#min60.com) https://stackoverflow.com/questions/19121276/uirefreshcontrol-incorrect-title-offset-during-first-run-and-sometimes-title-mis/
////////////////////////////////////////////////////////////////////////
- (void)beginRefreshingWithText:(NSString *)text {
[self setRefreshControlText:text];
[self beginRefreshing];
}
- (void)endRefreshingWithText:(NSString *)text {
[self setRefreshControlText:text];
[self.refreshControl endRefreshing];
}
- (void)beginRefreshing {
if (self.refreshControl == nil) {
return;
}
if (!self.refreshControlFixApplied) {
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.refreshControl.attributedTitle length] == 0) {
[self setRefreshControlText:#" "];
}
[self.refreshControl beginRefreshing];
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
dispatch_async(dispatch_get_main_queue(), ^{
// set the title before calling beginRefreshing
if ([self.refreshControl.attributedTitle length] == 0) {
[self setRefreshControlText:#" "];
}
if (self.tableView.contentOffset.y == 0) {
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
}
[self.refreshControl beginRefreshing];
self.refreshControlFixApplied = YES;
});
});
});
} else {
if (self.tableView.contentOffset.y == 0) {
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
}
[self.refreshControl beginRefreshing];
}
}
- (void)endRefreshing {
if (self.refreshControl == nil) {
return;
}
if (!self.refreshControlFixApplied) {
dispatch_async(dispatch_get_main_queue(), ^{
[self endRefreshing];
});
} else {
if (self.tableView.contentOffset.y < 0) {
self.tableView.contentOffset = CGPointMake(0, 0);
}
[self.refreshControl endRefreshing];
}
}
- (void)setRefreshControlText:(NSString *)text {
UIFont * font = [UIFont fontWithName:#"Helvetica-Light" size:10.0];
NSDictionary *attributes = #{NSFontAttributeName : font, NSForegroundColorAttributeName : [UIColor colorWithHex:0x00B92E]};
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attributes];
}
Use only methods
- (void)beginRefreshing;
- (void)beginRefreshingWithText:(NSString *)text;
- (void)endRefreshing;
- (void)endRefreshingWithText:(NSString *)text;

UIRefreshControl seems to still be broken on IOS9.3 when you change the attributedTitle while the tableView is pulled down. What seems to work is to subclass UIRefreshControl and force update its layout once the (attributed) title is changed.
The core fix is to trigger a change to the tableView contentOffset (causing some hidden magic in the _update method which layouts the spinner and text subviews) and additionally forcing the frame height to its expected value ensuring the background color fills up the pulled down region.
#implementation MEIRefreshControl
{
__weak UITableView* _tableView;
}
- (instancetype)initWithTableView:(UITableView*)tableView
{
self = [super initWithFrame:CGRectZero];
if (self)
{
_tableView = tableView;
}
return self;
}
#synthesize title = _title;
- (void)setTitle:(NSString *)title
{
if (!PWEqualObjects(_title, title))
{
_title = title;
self.attributedTitle = [[NSAttributedString alloc] initWithString:_title ? _title : #""];
[self forceUpdateLayout];
}
}
- (void)forceUpdateLayout
{
CGPoint contentOffset = _tableView.contentOffset;
_tableView.contentOffset = CGPointZero;
_tableView.contentOffset = contentOffset;
CGRect frame = self.frame;
frame.size.height = -contentOffset.y;
self.frame = frame;
}
#end

This is the code that seems to fix all the issues. Many of the others that involved beginning or ending refreshing where interfering with other parts of the control.
//This chunk of code is needed to fix an iOS 7 bug with UIRefreshControls
static BOOL refreshLoadedOnce = NO;
if (!refreshLoadedOnce) {
__weak typeof(self) weakself = self;
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.tableView.contentOffset = CGPointMake(0, -weakself.refreshControl.frame.size.height);
} completion:^(BOOL finished) {
weakself.refreshControl.attributedTitle = self.refreshControl.attributedTitle;
[weakself.refreshControl setNeedsUpdateConstraints];
[weakself.refreshControl setNeedsLayout];
refreshLoadedOnce = YES;
}];
}
//End of bug fix

I had the same problem, I did solve it by setting attributed text with space string to refresh control directly after init refresh control
_refreshControl = [[UIRefreshControl alloc]init];
[_refreshControl setAttributedTitle:[[NSAttributedString alloc]initWithString:#" "]];
After that, setting new attributed text to refresh control was without any problems.
[[self refreshControl] setAttributedTitle:[[NSAttributedString alloc]initWithString:[NSString stringWithFormat:#"Последнее обновление: %#", [dateFormat stringFromDate:[_post dateUpdated]]]]];
UPDATE
I noticed that problem come back when I use attrsDictionary:
this code works fine
NSAttributedString* attributedString = [[NSAttributedString alloc]initWithString:string];
[[self refreshControl] setAttributedTitle: attributedString];
and this make refreshControl's title appear directly after view loaded
NSAttributedString* attributedString = [[NSAttributedString alloc]initWithString:string attributes:attrsDictionary];
[[self refreshControl] setAttributedTitle: attributedString];
I didn't find solution yet.
UPDATE
Finally found solution, after refreshcontrol init set attributed string also with attributes:attrsDictionary
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects:[UIColor appDarkGray], [UIFont fontWithName:#"OpenSans-CondensedLight" size:14.0f], nil] forKeys:
[NSArray arrayWithObjects:NSForegroundColorAttributeName, NSFontAttributeName, nil]];
[_refreshControl setAttributedTitle:[[NSAttributedString alloc]initWithString:#" " attributes:attrsDictionary]];
so after that there is no problem to set new refreshcontrol's title.

The solution for me was to set a text in viewDidAppear, no need to call
beginRefreshing or endRefreshing on the mainQueue
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"d MMM, HH:mm"];
NSString *lastUpdated = [NSString stringWithFormat:NSLocalizedString(#"refresh_last_updated", nil),[formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:[[[DatabaseController sharedInstance] getCurrentSettings].lastTimeStamp doubleValue]]]];
UIFont *font = [UIFont fontWithName:FONT_LATO_LIGHT size:12.0f];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:lastUpdated attributes:#{NSFontAttributeName:font}];
_refreshControl.attributedTitle = attrString;
}

Related

uiview animation delays starting

I'm trying to display a continuously scrolling 'movie credits'. The VC code is shown below. The problem is that there is a ~12 second delay before the animation starts. Once the animation starts, the delay is not repeated between calls. The same behavior is seen on the simulator and a iPhone5.
An added bit of interest: When the VC pops, the app goes crazy with cpu use (100%+)... my laptop will hit 200°.
Apparently it's the initial animation that is not firing. If the completion block is commented out, no animation ever happens. So the 12 second delay is actually the first run of the animation not doing anything then the second invocation actually makes something happen on the screen.
Can someone explain what I'm doing wrong or point me to the appropriate docs.
- (void)loopCredits
{
CGRect startFrame = _creditsView.frame;
CGRect endFrame = CGRectMake(0, -568, 320, 568);
[UIView animateWithDuration:10.0
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.creditsView.frame = endFrame;
}
completion:^(BOOL finished) {
self.creditsView.frame = startFrame;
[self performSelector:#selector(loopCredits) withObject:nil afterDelay:0.0];
}
];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = NO;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// [self loopCredits];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self createInfoString];
self.creditsView.attributedText = self.text;
[self loopCredits];
}
- (void)createInfoString
{
NSString* path = [[NSBundle mainBundle] pathForResource:#"InfoPageText" ofType:#"plist"];
NSURL* pathURL = [[NSURL alloc] initFileURLWithPath:path];
NSArray* temp = [NSArray arrayWithContentsOfURL:pathURL];
NSUInteger strLength = [[temp objectAtIndex:0] length];
self.text = [[NSMutableAttributedString alloc] initWithString:[temp objectAtIndex:0]];
UIFont* font = [UIFont fontWithName:#"Chalkduster" size:18.0f];
UIColor* textColor = [UIColor colorWithRed:250.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1];
[_text addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, strLength)];
[_text addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, strLength)];
}

Parent child navigation UIViewController causes exception for editing form

I have a parent->child navigation setup in application. I use navigation via pushViewController function.
-(void)loadMemosViewController:(id)sender{
if(activeHullGuid != nil && activeHullGuid.length > 0)
{
NSString *storyboardName = #"MainStoryboard_iPhone1";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
MemosViewController *loginVC = [storyboard instantiateViewControllerWithIdentifier:#"sid_Memos"];
loginVC.keyReference = [[KeyValuePairIS alloc] initWithData:&controllerID:activeHullGuid];
[self.navigationController pushViewController:loginVC animated:YES];
}
}
for back navigation I use only default implementation in IOS (that would be a click on a back button).
This setup works for most situations, but recent implementation is causing problems.
The problem is this:
I have parent view controller named "hullViewController" and a child "memosViewController". The navigation between them works. Child does not report any information back to parent. HullViewController is also an editable form, which changes edit state via button in navigation bar.
Now if I change this edit/read state on hullViewController works nonstop. If I visit the child memosViewController, and go back to parent, I can only change state once more, then application crashes with exc_bad_access code=1.
After profiling with "Zombies" I found the culprit for exception is my probably disposed child memosViewController.
An Objective-C message was sent to a deallocated 'MemosViewController' object (zombie) at address: 0xdd52f10
it seams to crash on an IOS internal event, since none of my breakpoints are hit before crash.
A you can see the child is instanced during creation and I don't reference it to nothing else. Why would the edit state change request the child object?
What I tried already:
-declaring MemosViewController as a class variable. (application did not crash anymore, but would not change state anymore).
-initialising MemosViewController on viewDidLoad, changed nothing.
-calling child with class init only (not via storyboard), loaded child without UI, but result was same.
Project is set up with ARC, so I have minimum control on disposal of objects.
I have been searching for a solution quite a while now, with no results. Any help to solve my error editing if I visit the child would be appreciated.
UPDATE
I have additionally discovered, that when I get back to parent from child, the reference self.navigationItem still points to child, and any update to navigation buttons crashes the app.
**attaching custom ViewController, since it could be related to problem **
#import "UITableViewControllerEx.h"
#import "UITextFieldEx.h"
#import "UITextViewEx.h"
#import "GlobalValues.h"
#import "UITableViewEx.h"
#interface UITableViewControllerEx ()
#end
#implementation UITableViewControllerEx
UIBarButtonItem *bbi_navigateToMaster;
UIBarButtonItem *editButton;
UIButton *cmdEdit;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self setNavigationBackground];
[self setApplicationTintColor];
[self setApplicationTitleFont];
[self setupLeftBarButtonItem];
[self setBackButton];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//UITextFieldEx delegate to control the length of fields
- (BOOL)textField:(UITextFieldEx *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > textField.maxLength) ? NO : YES;
}
//UITextViewEx delegate to control the length of fields
-(BOOL)textView:(UITextViewEx *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSUInteger newLength = [textView.text length] + [text length] - range.length;
return (newLength > textView.maxLength) ? NO : YES;
}
//function to set left button to always pop to root controller
- (void)setBackButtonToReturnToMaster {
UIButton *cmdHome = [[UIButton alloc] initWithFrame:CGRectMake(0,0,30,30)];
[cmdHome setImage:[UIImage imageNamed:#"home"] forState:UIControlStateNormal];
bbi_navigateToMaster = [[UIBarButtonItem alloc] initWithCustomView:cmdHome];
[cmdHome addTarget:self action:#selector(backToMaster:) forControlEvents:UIControlEventTouchUpInside ];
self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:bbi_navigateToMaster , nil];
/*
bbi_navigateToMaster = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:self action:#selector(backToMaster:)];
self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:bbi_navigateToMaster , nil];
[bbi_navigateToMaster setImage:[UIImage imageNamed:#"home"]];
[bbi_navigateToMaster setImageInsets:UIEdgeInsetsMake(2, 2, 2, 2)];*/
}
//pop to root controller
-(void)backToMaster:(id)sender {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
}
else { [self.navigationController popToRootViewControllerAnimated:YES]; }
}
//find superview element of given type
- (UIView *)findSuperViewWithClass:(Class)superViewClass uiViewToSearch:(UIView*)bottomView{
UIView *superView = bottomView.superview;
UIView *foundSuperView = nil;
while (nil != superView && nil == foundSuperView) {
if ([superView isKindOfClass:superViewClass]) {
foundSuperView = superView;
break;
} else {
superView = superView.superview;
}
}
return foundSuperView;
}
-(void)setNavigationBackground{
if ([self.navigationController.navigationBar respondsToSelector:#selector(setBackgroundImage:forBarMetrics:)] ) {
UIImage *image = [UIImage imageNamed:#"navigationBackground"];
[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
UIView* uv = [[UIView alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.size.height-1,self.navigationController.navigationBar.frame.size.width, 1)];
[uv setBackgroundColor:[GlobalValues getTintColor]];
[self.navigationController.navigationBar insertSubview:uv atIndex:10];
}
}
//sets the tint color of szstem items (title, szstem buttons, ...)
-(void)setApplicationTintColor {
NSArray *ver = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[ver objectAtIndex:0] intValue] >= 7) {
self.navigationController.navigationBar.barTintColor = [GlobalValues getTintColor];
self.navigationController.navigationBar.tintColor = [GlobalValues getTintColor];
self.navigationController.navigationBar.translucent = NO;
[self.navigationController.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}];
UIColor *color = [GlobalValues getTintColor];
self.view.tintColor = color;
}else {
//self.navigationController.navigationBar.tintColor = [GlobalValues getTintColor];
/*NSDictionary *textTitleOptions = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], UITextAttributeTextColor, [UIColor clearColor], UITextAttributeTextShadowColor, nil];
[[UINavigationBar appearance] setTitleTextAttributes:textTitleOptions];*/
}
}
//sets the navigation title
-(void)setApplicationTitleFont {
NSArray *ver = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[ver objectAtIndex:0] intValue] >= 7) {
[self.navigationController.navigationBar setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"HelveticaNeue-Light" size:21],
NSFontAttributeName, [UIColor whiteColor], UITextAttributeTextColor, [UIColor clearColor], UITextAttributeTextShadowColor, nil]];
}else {
[self.navigationController.navigationBar setTitleTextAttributes: #{
UITextAttributeTextColor: [UIColor whiteColor],
UITextAttributeFont: [UIFont fontWithName:#"Helvetica-Light" size:21.0f]
}];
}
}
-(void)setupLeftBarButtonItem{
cmdEdit = [[UIButton alloc] initWithFrame:CGRectMake(0,0,30,30)];
[cmdEdit setImage:[UIImage imageNamed:#"locked"] forState:UIControlStateNormal];
editButton = [[UIBarButtonItem alloc] initWithCustomView:cmdEdit];
[cmdEdit addTarget:self action:#selector(setEditState) forControlEvents:UIControlEventTouchUpInside];
}
- (UIBarButtonItem *)leftBarButtonItem
{
if (self.tableView.editing) {
[cmdEdit setImage:[UIImage imageNamed:#"unlocked"] forState:UIControlStateNormal];
return editButton;
}
else {
[cmdEdit setImage:[UIImage imageNamed:#"locked"] forState:UIControlStateNormal];
return editButton;
}
}
-(void)updateEditButton{
if (self.tableView.editing) {
[cmdEdit setImage:[UIImage imageNamed:#"unlocked"] forState:UIControlStateNormal];
}
else {
[cmdEdit setImage:[UIImage imageNamed:#"locked"] forState:UIControlStateNormal];
}
}
-(void)setEditState{
if (!self.tableView.editing) {
[self setEditing:YES animated:YES];
} else {
[self setEditing:NO animated:YES];
}
[self updateEditButton];
}
}*/
-(void) setBackButton{
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backBtnImage = [UIImage imageNamed:#"back"] ;
[backBtn setBackgroundImage:backBtnImage forState:UIControlStateNormal];
[backBtn addTarget:self action:#selector(goback) forControlEvents:UIControlEventTouchUpInside];
backBtn.frame = CGRectMake(0, 0, 30, 30);
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:backBtn] ;
self.navigationItem.leftBarButtonItem = backButton;
}
- (void)goback
{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - Table view data source
#pragma mark - Table view delegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundView=[[UIView alloc] initWithFrame:CGRectZero];
cell.backgroundColor = [UIColor clearColor];
cell.layer.backgroundColor = [UIColor clearColor].CGColor;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *customTitleView = [ [UIView alloc] initWithFrame:CGRectMake(10, 0, 300, 44)];
UIView *customTitleLineView = [ [UIView alloc] initWithFrame:CGRectMake(10, 43, self.view.frame.size.width -20, 0.5f)];
customTitleLineView.backgroundColor = [GlobalValues getTintColor];
UILabel *titleLabel = [ [UILabel alloc] initWithFrame:CGRectMake(20, 0, 300, 44)];
titleLabel.text = [self tableView:tableView titleForHeaderInSection:section];
titleLabel.font = [UIFont fontWithName:#"HelveticaNeue" size:18];
titleLabel.textColor = [GlobalValues getTintColor];
titleLabel.backgroundColor = [UIColor clearColor];
if (titleLabel.text.length != 0) {
[customTitleView addSubview:customTitleLineView];
}
[customTitleView addSubview:titleLabel];
return customTitleView;
}
#end
Seems I have found a solution to my problem.
Class UITableViewControllerEx contains functionality to setup edit button. The class variable "UIBarButtonItem *editButton;" is then used as edit button on all forms that inherit from "UITableViewControllerEx"
the solution was to instantiate UIBarButtonItem on each form inheriting UITableViewControllerEx with local name (like editButtonHull) and given as param to logic of superclass.
Thanks to #akashg for suggestion that Navigation bar modification might be the problem

Getting memory leak in UIKit?

when I tested my App in instruments for memory leak I found nothing(running using simulator).But When I run it in a mobile and then checked, there are many leaks in UIKit objects. This happening in every view.In simulator no such leaks are showing.
Below is the screenshot of the instrument where some leakage happened.
When I moved to secondViewController from HomeView, no leaks found.If again coming back to home,these many leaks are found. So, is it mean that, I have to release/nil all the UI objects which I used in that secondView. For your information, below are the UI objects I used in secondView.
1.Two Background UIImageView
2.One TitleBar UIImageView
3.3 UIButtons(Back,left and right button for iCarousel)
4.One iCarousel view
5.UIPageController(For this I have used a third Party code SMPageControl)
6.One title label.
Note : Mine is Non-ARC code.
Did anyone faced this problem before.How can I overcome this problem,since I have this problem in every View in my App.Because of this, my App getting memory waring frequently and crashing often.
Thank you.
Below is the my implementation file of that View.
EDIT1 :
#implementation CatalogueViewController
#synthesize deptCarousel = _deptCarousel;
#synthesize carouselItems = _carouselItems;
#synthesize categorymAr = _categorymAr;
#synthesize spacePageControl = _spacePageControl;
#synthesize wrap;
- (void)dealloc {
_deptCarousel = nil;
[_categorymAr release];
_categorymAr = nil;
_deptCarousel.delegate = nil;
_deptCarousel.dataSource = nil;
[_deptCarousel release];
[_carouselItems release];
[viewGesture release];
viewGesture = nil;
[_spacePageControl release];
_spacePageControl = nil;
imgViewBG = nil;
imgViewBG2 = nil;
btnPrev = nil;
btnNext = nil;
// [self releaseObjects];
[super dealloc];
}
- ( IBAction) btnBackClicked {
[self.navigationController popViewControllerAnimated:YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"catalogue", #"Catalogue");
// Do any additional setup after loading the view from its nib.
_deptCarousel.type = iCarouselTypeLinear;
_deptCarousel.scrollSpeed = 0.3f;
_deptCarousel.bounceDistance = 0.1f;
_deptCarousel.scrollToItemBoundary = YES;
_deptCarousel.stopAtItemBoundary = YES;
[_deptCarousel setScrollEnabled:NO];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeNext:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[viewGesture addGestureRecognizer:swipeLeft];
[swipeLeft release];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipePrev:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[viewGesture addGestureRecognizer:swipeRight];
[swipeRight release];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[viewGesture addGestureRecognizer:singleTap];
[singleTap release];
_carouselItems = [[NSMutableArray alloc] initWithCapacity:1];
_categorymAr = [[NSMutableArray alloc] initWithCapacity:1];
[self addCatalogues];
_spacePageControl.numberOfPages = [_categorymAr count];
[_spacePageControl setPageIndicatorImage:[UIImage imageNamed:IS_IPAD?#"Marker1.fw.png" : #"Markeri.png"]];
[_spacePageControl setCurrentPageIndicatorImage:[UIImage imageNamed:IS_IPAD?#"Marker-Highlight.png" : #"Marker-Highlight_i.png"]];
[_spacePageControl addTarget:self action:#selector(spacePageControl:) forControlEvents:UIControlEventValueChanged];
}
- (void)spacePageControl:(SMPageControl *)sender{
[_deptCarousel scrollToItemAtIndex:sender.currentPage animated:YES];
}
- ( void ) addCatalogues {
[_categorymAr addObjectsFromArray:[[DBModel database] categoryList]];
for (int i = 0; i < [_categorymAr count]; i++) {
[_carouselItems addObject:[NSNumber numberWithInt:i]];
}
[_deptCarousel reloadData];
}
- (void)viewDidUnload{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[self phoneType];
[super viewWillAppear:animated];
if (IS_IPAD) {
UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation];
[self handleOrientation:statusBarOrientation];
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- ( void ) phoneType{
if(!IS_IPAD){
if(IS_IPHONE5){
imgViewBG.image = [UIImage imageNamed:#"Background5_5.jpg"];
imgViewBG.center = CGPointMake(162,265);
imgViewBG2.image = [UIImage imageNamed:#"Background11_5.png"];
_spacePageControl.center = CGPointMake(160, 478);
_deptCarousel.center = CGPointMake(160, 355);
viewGesture.center = CGPointMake(160, 355);
btnPrev.center = CGPointMake(25, 355);
btnNext.center = CGPointMake(295, 355);
}
else{
imgViewBG.image = [UIImage imageNamed:#"Background5.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background9.png"];
}
}
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
textFieldSearch.placeholder = #"";
UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[clearButton setImage:[UIImage imageNamed:IS_IPAD?#"Btn_X_Large.fw.png":#"Btn_X.fw.png"] forState:UIControlStateNormal];
[clearButton addTarget:self action:#selector(btnClearTextField) forControlEvents:UIControlEventTouchUpInside];
[textFieldSearch setRightViewMode:UITextFieldViewModeAlways];
[textFieldSearch setRightView:clearButton];
[clearButton release];
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
[textFieldSearch setRightView:nil];
if ([textFieldSearch.text isEqualToString:#""]) {
textFieldSearch.placeholder = NSLocalizedString(#"hud_search_for_a_product_here",#"");
}
}
-(IBAction)btnClearTextField{
textFieldSearch.text = #"";
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (IS_IPAD) {
return YES;
} else {
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation )toInterfaceOrientation duration:(NSTimeInterval)duration{
if (IS_IPAD) {
[self handleOrientation:toInterfaceOrientation];
}
}
- ( void ) handleOrientation:(UIInterfaceOrientation )toInterfaceOrientation {
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
imgViewBG.image = [UIImage imageNamed:#"Background_Catalogue_P.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background_Overlay_P.fw.png"];
btnPrev.center = CGPointMake(90, 640);
btnNext.center = CGPointMake(677, 640);
textFieldSearch.frame = CGRectMake(187, 54, 418, 25);
_deptCarousel.frame = CGRectMake(235, 250, 300, 800);
_spacePageControl.center = CGPointMake(385, 920);
viewGesture.center = CGPointMake(385, 658);
}else {
imgViewBG.image = [UIImage imageNamed:#"Background_Catalogue_L.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background_Overlay_L.fw.png"];
btnPrev.center = CGPointMake(54, 385);
btnNext.center = CGPointMake(640, 385);
textFieldSearch.frame = CGRectMake(240, 55, 567, 25);
_deptCarousel.frame = CGRectMake(50, 250, 600, 300);
_spacePageControl.center = CGPointMake(346, 660);
viewGesture.center = CGPointMake(347, 405);
}
}
- ( IBAction )btnDepartmentClicked:(id)sender {
int btnTag = [sender tag];
ProductCategoriesViewController *productView = [[ProductCategoriesViewController alloc] initWithNibName:#"ProductCategoriesView" bundle:nil];
if ( btnTag == 0 ) {
[productView setStrTitle:NSLocalizedString(#"women", #"Women")];
}else if ( btnTag == 1 ) {
[productView setStrTitle:NSLocalizedString(#"men", #"Men")];
} else {
[productView setStrTitle:NSLocalizedString(#"sports", #"Sports")];
}
[self.navigationController pushViewController:productView animated:YES];
[productView release];
}
- ( BOOL ) textFieldShouldReturn:( UITextField * )textField {
[textField resignFirstResponder];
[Flurry logEvent:#"Product searched" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:textField.text,#"1", nil]];
[self productSearch:textField.text isBar:NO isQR:NO];
return YES;
}
- ( void ) productSearch:( NSString * )_searchText isBar:( BOOL )_isBar isQR:( BOOL )_isQr {
if ([_searchText isEqualToString:#""]) {
return;
}
NSMutableArray *ProductList = [[NSMutableArray alloc] init];
[ProductList addObjectsFromArray:[[DBModel database] productSearch:_searchText isBar:_isBar isQR:_isQr]];
if ( [ProductList count] == 0 ) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"product", #"")
message:NSLocalizedString(#"cannot_find_product", #"")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"ok", #"")
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
GeneralProductListViewController *generalProductList = [[GeneralProductListViewController alloc] initWithNibName:IS_IPAD?#"GeneralProductListView~iPad": #"GeneralProductListView" bundle:nil];
[generalProductList setMArProducts:ProductList];
[self.navigationController pushViewController:generalProductList animated:YES];
[generalProductList release];
}
[ProductList release];
}
-(IBAction) spin:(id)sender {
if([sender tag]==0)
{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];
// [_deptCarousel scrollByNumberOfItems:1 duration:2.0];
}
else{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];
}
}
-(void)swipeNext:(UISwipeGestureRecognizer *)recognizer{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];
}
-(void)swipePrev:(UISwipeGestureRecognizer *)recognizer{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];
}
-(void) handleSingleTap:(UITapGestureRecognizer *)recognizer{
if ([_categorymAr count] > 0) {
ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ?
#"ProductCategoriesView~iPad" : #"ProductCategoriesView" bundle:nil];
Category *categoryObj = [_categorymAr objectAtIndex:[self.deptCarousel currentItemIndex]];
[prodCatView setStrTitle:categoryObj.categoryName];
[prodCatView setCategoryId:categoryObj.categoryId];
[Flurry logEvent:#"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:#"%d",categoryObj.categoryId], nil]];
[self.navigationController pushViewController:prodCatView animated:YES];
[prodCatView release];
}
}
//-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// pageControl.currentPage = [self.deptCarousel currentItemIndex] ;
//}
#pragma mark
#pragma mark NavigationBarViewDelegate metho
- ( void ) navigationBackClicked {
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark iCarousel methods
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return [_carouselItems count];
}
- (NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel
{
//limit the number of items views loaded concurrently (for performance reasons)
return NUMBER_OF_VISIBLE_ITEMS;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index
{
Category *categoryObj = [_categorymAr objectAtIndex:index];
//create a numbered view
UIView *view = nil;
NSString *imagePath = [[APP_CACHES_DIR stringByAppendingPathComponent:#"catalogues"] stringByAppendingString:[NSString stringWithFormat:#"/%d.jpg", categoryObj.categoryId]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:IS_IPAD?#"Gallery Placeholder.png":#"Gallery Placeholder.png"]] autorelease];
} else {
view = [[[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[[APP_CACHES_DIR stringByAppendingPathComponent:#"catalogues"] stringByAppendingString:[NSString stringWithFormat:#"/%d.jpg", categoryObj.categoryId]]]] autorelease];
}
if (IS_IPAD) {
view.frame = CGRectMake(0, 0, 420, 420);
} else {
view.frame = CGRectMake(0, 0, 200, 200);
}
// UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(view.bounds.origin.x, view.bounds.origin.y+view.bounds.size.height, view.bounds.size.width, 44)] autorelease];
// label.text = categoryObj.categoryName;
// label.textColor = [UIColor blackColor];
// label.backgroundColor = [UIColor clearColor];
// label.textAlignment = UITextAlignmentCenter;
// label.font = [UIFont fontWithName:#"Helvetica-Bold" size:IS_IPAD?26:14];
// [view addSubview:label];
return view;
}
- (NSUInteger)numberOfPlaceholdersInCarousel:(iCarousel *)carousel
{
//note: placeholder views are only displayed on some carousels if wrapping is disabled
return INCLUDE_PLACEHOLDERS? 2: 0;
}
- (UIView *)carousel:(iCarousel *)carousel placeholderViewAtIndex:(NSUInteger)index
{
//create a placeholder view
UIView *view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#""]] autorelease];
UILabel *label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
label.text = (index == 0)? #"[": #"]";
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
label.font = [label.font fontWithSize:50];
_spacePageControl.currentPage = index;
// [view addSubview:label];
return view;
}
- (CGFloat)carouselItemWidth:(iCarousel *)carousel
{
//usually this should be slightly wider than the item views
return ITEM_SPACING;
}
- (CATransform3D)carousel:(iCarousel *)_carousel transformForItemView:(UIView *)view withOffset:(CGFloat)offset
{
//implement 'flip3D' style carousel
//set opacity based on distance from camera
view.alpha = 1.0 - fminf(fmaxf(offset, 0.0), 1.0);
//do 3d transform
CATransform3D transform = CATransform3DIdentity;
transform.m34 = _deptCarousel.perspective;
transform = CATransform3DRotate(transform, M_PI / 8.0, 0, 1.0, 0);
return CATransform3DTranslate(transform, 0.0, 0.0, offset * _deptCarousel.itemWidth);
}
- (BOOL)carouselShouldWrap:(iCarousel *)carousel
{
//wrap all carousels
// return NO;
return wrap;
}
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
if (index == [self.deptCarousel currentItemIndex]) {
ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ?
#"ProductCategoriesView~iPad" : #"ProductCategoriesView" bundle:nil];
Category *categoryObj = [_categorymAr objectAtIndex:index];
[prodCatView setStrTitle:categoryObj.categoryName];
[prodCatView setCategoryId:categoryObj.categoryId];
[Flurry logEvent:#"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:#"%d",categoryObj.categoryId], nil]];
[self.navigationController pushViewController:prodCatView animated:YES];
[prodCatView release];
}
}
-(void) carouselDidScroll:(iCarousel *)carousel{
// [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+3 animated:YES];
// [_deptCarousel scrollByNumberOfItems:1 duration:1];
}
- (void)carouselCurrentItemIndexUpdated:(iCarousel *)carousel{
_spacePageControl.currentPage = [self.deptCarousel currentItemIndex];
}
- ( IBAction ) myCart {
if ( [[DBModel database] isShoppingListEmpty] ) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"at_shopping_cart", #"")
message:NSLocalizedString(#"amsg_shopping_cart_empty", #"")
delegate:nil cancelButtonTitle:NSLocalizedString(#"ok", #"") otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
MyCartViewController *myCartView = [[MyCartViewController alloc] initWithNibName:IS_IPAD ? #"MyCartView~iPad" : #"MyCartView" bundle:nil];
[self.navigationController pushViewController:myCartView animated:YES];
[myCartView release];
}
First, as noted before, use ARC. There is no single thing you could do that will more improve memory management.
Whether you use ARC or not, you should always use accessors to access your ivars (except in init and dealloc). As noted by #LombaX, you're setting your ivars incorrectly in viewDidLoad. Using accessors would help this.
You should run the static analyzer, which will help you find other memory mistakes.
I would suspect that you have an IBOutlet that is configured as retain and that you are not releasing in dealloc. That is the most likely cause of the leaks I'm seeing in your screenshots. ARC will generally make such problems go away automatically.
It is very possible that you have a retain loop. This generally would not show up as a leak. You should use heapshot to investigate that. Your leaks are pretty small; they may not be the actual cause of memory warnings. What you want to investigate (with the Allocations instrument) is what is actually significantly growing your memory use.
But first ARC. Then accessors. Then remove all build warnings. Then remove all Static Analyzer warnings. Then use the Allocations instrument.
Side note: the fact that it says the responsible party is "UIKit" does not mean that this is a bug in UIKit. It just means that UIKit allocated the memory that was later leaked. The cause of the leak could be elsewhere. (That said, UIKit does have several small leaks in it. In general they should not give you trouble, but you may never be able to get rid of 100% of small leaks in an iOS app.)
First:
you have a possible and visible leak, but I'm not sure if it is the same leak you have found in instruments:
These two lines are in your viewDidLoad method
_carouselItems = [[NSMutableArray alloc] initWithCapacity:1];
_categorymAr = [[NSMutableArray alloc] initWithCapacity:1];
But: viewDidLoad: is called every time the view is loaded by it's controller. If the controller purges the view (for example after a memory warning), at the second viewDidLoad your _carouselItems and _categorymAr instance variables will lost the reference to the previously created NSMutableArray, causing a leak
So, change that lines and use the syntesized setters:
self.carouselItems = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
self.categorymAr = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
the syntesized setter is configured to release the previous object before assignin a new one.
However: it's possible that you have another leak.
If you can reproduce the leak simply (if I understand, the leak appears simply moving from a VC to another), you can use the "heapshot" function of instruments.
Assuming that your leak appears moving from the first VC to the second and coming back:
open instruments with the allocations tool
go from the first VC to the second and come back.
press "mark heap" on the left. A line will appear.
go again from the first VC to the second and come back.
press "heapshot" again
do this several times (9-10)
the heapshot tool takes a "snapshot" of the living objects at the time you pushed the button and shows you only the difference.
If there are 2-3 new objects, you will see it in the list.
This is a good starting point to investigate a leak.
Look at the attached image:
Consider that you must mark the heap several time and discriminate "false positive" by looking at the object created, in my example you can se a possible leak (heapshot5, 1,66KB), but after looking at the content it's not --> it was a background task that started in that moment.
Moreover, delays of the autorelease pool and the cache of some UIKit objects can show something in the heapshot, this is why I say to try it several times.
One easy way to detect where your leaks come from is to use the Extended Detail view of the Instruments.
To do that click on "View"->"Extended detail" and a right menu with the stack trace of the "leak" will appear. There you will easily find the leaking code for each leak and if they come from your app.

Determine if current screen has visible navigation bar

I have a singlton object. Is there any simple way to determine if current screen contains a navigation bar within singlton methods?
The singleton is UIView subclass. It's designed for showing prorgess activity, e.g. network exchange. It looks like black rectangle dropping down from top and hiding when the work is done. Why singleton? It's easy to call it from any place of code
The followed snippet is showing the initialization of activity singleton and published here just for better understaning my idea.
-(void) showUpdatingView:(NSString *) msg {
[self initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
activity = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
activity.frame = CGRectMake(5, 10, 22, 22);
labelView = [[[UILabel alloc] initWithFrame:CGRectMake(35, 10, [UIScreen mainScreen].bounds.size.width - 10, 22)] autorelease];
labelView.font = [UIFont boldSystemFontOfSize:12];
labelView.backgroundColor = [UIColor clearColor];
labelView.textColor = [UIColor whiteColor];
labelView.text = msg;
[self addSubview:activity];
[self addSubview:labelView];
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.7;
}
The activity can be called by
[[ActivitySingleton getInstance] showUpdatingView:#"Getting data."];
it's not all.
The singleton is being created in AppDelegate object and the view is added to
inlineActivity = [[CHInlineActivityView alloc] initView];
[self.window.rootViewController.view addSubview:inlineActivity];
I know it may look crazy. But when I was designing it seemed to me reasonable
if you have all in one navigationController:
BOOL navHidden = self.window.rootViewController.navigationController.navigatonBarHidden;
if you don't it is a bit harder.. you could check the window's subviews and see if you can find a UINavigationBar
id navbar = [self.window firstSubviewOfKind:[UINavigationBar class] withTag:NSNotFound];
BOOL navHidden = navbar == nil;
#implementation NSView (findSubview)
- (NSArray *)findSubviewsOfKind:(Class)kind withTag:(NSInteger)tag inView:(NSView*)v {
NSMutableArray *array = [NSMutableArray array];
if(kind==nil || [v isKindOfClass:kind]) {
if(tag==NSNotFound || v.tag==tag) {
[array addObject:v];
}
}
for (id subview in v.subviews) {
NSArray *vChild = [self findSubviewsOfKind:kind withTag:tag inView:subview];
[array addObjectsFromArray:vChild];
}
return array;
}
#pragma mark -
- (NSView *)firstSubviewOfKind:(Class)kind withTag:(NSInteger)tag {
NSArray *subviews = [self findSubviewsOfKind:kind withTag:tag inView:self];
return subviews.count ? subviews[0] : nil;
}
#end

textFieldShouldBeginEditing not being called in custom class (delegate set)

I have a custom class like this:
#interface formParser : NSObject <UITextFieldDelegate> {
....
and in the .m I create a UITextField element like this:
UITextField *ui = [[UITextField alloc] initWithFrame:CGRectMake(left, top, width, height)];
[ui setDelegate:self];
[ui setPlaceholder:[dict_elementInfo objectForKey:#"placeholder"]];
[ui setBorderStyle:UITextBorderStyleLine];
[view addSubview:ui];
and
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
NSLog(#"should begin");
return NO;
}
My problem is that the shouldbegin is never called. When I try this technique on a "normal" UIViewController class it works perfectly, but doing this in my custom object it it never called.. Can anyone figure out why?
My custom class is called as follows:
formParser *fParse = [[formParser alloc] init];
UIView *view_formBackground = [fParse viewOfPlist:#"form" initSize:CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height)];
view_formBackground.backgroundColor = [UIColor whiteColor];
//add views to main view
[scrollView addSubview:view_formBackground];
[self.view addSubview:scrollView];
Also, in formparser.m the viewofplist is as follows:
-(UIView *)viewOfPlist:(NSString *)filename initSize:(CGRect)size
{
ypos_element_left = 40; ypos_element_right = 40;
view = [[UIView alloc] initWithFrame:size];
//load plist
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
rootArray = [dict objectForKey:#"form"];
//loop door alle UI entries in de dict.
for (NSDictionary *dict_UIElement in rootArray)
{
NSString *UIType = [dict_UIElement objectForKey:#"type"];
if ([UIType isEqualToString:#"ui_empty"]) [self handle_uiempty:dict_UIElement];
if ([UIType isEqualToString:#"ui_multiselect"]) [self handle_uimultiselect:dict_UIElement];
if ([UIType isEqualToString:#"ui_label"]) [self handle_uilabel:dict_UIElement];
if ([UIType isEqualToString:#"ui_textfield"]) [self handle_uitextfield:dict_UIElement];
if ([UIType isEqualToString:#"ui_choicefield"]) [self handle_uichoicefield:dict_UIElement];
if ([UIType isEqualToString:#"ui_calendar"]) [self handle_uicalendar:dict_UIElement];
}
return (view);
}
Thanks for answering!
Is one of your allocations falling out of scope and being cleaned up by ARC?
Helpful link on how the responder chain works..
http://developer.apple.com/library/ios/#documentation/general/conceptual/Devpedia-CocoaApp/Responder.html

Resources