textFieldShouldBeginEditing not being called in custom class (delegate set) - ios

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

Related

Custom UIView and setting and getting custom value back from variable inside UIView

I have a custom uiview where i have a setter and a getter when the uiview is dynamically created i set this value like this:
for(NSDictionary *dictCategory in arrCategoryList)
{
NSString *strCategoryId = [dictCategory objectForKey:#"CategoryId"];
NSString *strCategoryName = [dictCategory objectForKey:#"Name"];
NSLog(#"%# : %#",strCategoryId,strCategoryName);
UIViewMenuItem *linkMenu = [[UIViewMenuItem alloc] init];
[linkMenu setFrame:CGRectMake(10, i+1, 300, 35)];
[linkMenu setId:strCategoryId]; //here i set the value in the custom uiview
linkMenu.layer.zPosition = 7;
[viewSlide3 addSubview:linkMenu];
[linkMenu setBackgroundColor:[UIColor blueColor]];
linkMenu.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:.9];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[linkMenu addGestureRecognizer:singleFingerTap];
UILabel *labelMenu = [[UILabel alloc] init];
[labelMenu setFrame:CGRectMake(20, 0, 300, 35)];
[labelMenu setFont:[UIFont systemFontOfSize:16]];
[labelMenu setTextColor:[UIColor whiteColor]];
[linkMenu addSubview:labelMenu];
[labelMenu setText:strCategoryName];
i = i + 35 + 1;
}
Now when i tap on the custom uiview i want to get back the value from the custom uiview so I'm doing this:
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
CGPoint touchPoint=[recognizer locationInView:[recognizer.view superview]];
UIViewMenuItem *tempView = (UIViewMenuItem *)recognizer.view;
NSNumber *tag = [NSNumber numberWithInt:tempView.tag];
NSString *idCat = [tempView getCatId];
NSLog(#"TAG %#",idCat);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: [NSString stringWithFormat:#"http://localhost:8888/MAMP/WHFC/SubCategories.php?categoryid=%d", idCat]]];
int i = 0;
NSError *e;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&e];
NSArray *arrCategoryList = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&e];
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor whiteColor];
UIView *uiView = [[UIView alloc] init];
[uiView setFrame:CGRectMake(0, 480, 320, 480)];
[uiView setBackgroundColor:[UIColor grayColor]];
viewController.view = uiView;
UITableView *uiTableView = [[UITableView alloc] init];
[uiTableView setFrame:CGRectMake(0, 0, 320, 480)];
[uiView addSubview:uiTableView];
[self presentViewController:viewController animated:YES completion:nil];
//Do stuff here...
}
But i keep get the same value "13" from NSString *idCat = [tempView getCatId];
This is the custom UIView class:
#import <UIKit/UIKit.h>
#interface UIViewMenuItem : UIView
- (void) setId: (NSString *) cId;
- (NSString *) getCatId;
#end
NSString *catId;
#import "UIViewMenuItem.h"
#implementation UIViewMenuItem
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void) setId: (NSString *) cId;
{
catId = cId;
//If possible, set things up for the new word
}
- (NSString *) getCatId{
return catId;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
There is nothing wrong, in principle, with using a hidden (not visible from outside the class) instance variable cId and providing getters and setters.
But yours isn't an instance variable. It is declared somewhere between the interface and the implementation. It's a global variable or static. (I am not 100% positive about the global, but I think it is. I ran into a linker issue - dublicate object - once when I did the same mistake and did it in two classes using the same variable name. However, it is not that important whether it is global or just static. Being static is bad enough.)
This means at least that all the instances of UIViewMenuItem share the same variable (!!!).
First:
Move it to somewhere between #implementation and its #end.
Then it should work as expected.
Then:
Be lazy and solve it the objective-c-way. Get rid of the variable and get rid of the getter and setter.
If you are happy with the variable being public (it's accessible though getter and setter anyway) then just add a #property (nonatomic, retain) NSString *cid; to the interface. Unless you've got an older compiler then that is basically it. The compiler will add a getter and a setter (getCId and cId) automatically.
The compiler will add an iVar _cId that you would not use yourself in most cases. I am not 100% positive whether the name of the iVar will be cId or _cId when you use the comfortable way. If you care then you can conrol the name of the iVar by adding an #synthesize statment to the implementation and define the iVar name as you like. You could add much more customization (again declaring the iVar yourself, providing custom getters and setters) but there is no need for that when all you need from the property is what you have shown in your question and its code examples.

When I first load a Detail view from Master View it takes twice as long as each time after that

I have a UITableViewController with 60 cells. The detail view for the cells have 5 imageViews and 5 labels. When I press on a cell for the first time, it takes 2-3 seconds to load the detail view. When I go back to the MasterView and press on a cell, the same one or a different one, it is instantaneous. What could cause this massive lag and how could I fix it?
#implementation DetailViewController{
NSArray *nameArray;
NSArray *flag;
NSArray *pop;
NSArray *yearOfUnion;
NSArray *area;
NSArray *city;
NSArray *abbreviations;
NSArray *resNamea;
NSArray *mainViewa;
NSArray *plateViewa;
}
#synthesize passDataTest;
#synthesize scrollView;
#synthesize stateint;
#synthesize cgvalue;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%f", cgvalue);
[scrollView setScrollEnabled:YES];
if ([[UIScreen mainScreen] bounds].size.height == 480) {
[scrollView setContentSize:CGSizeMake(320, 920)];
} else {
[scrollView setContentSize:CGSizeMake(320, 834)];
}
[scrollView addSubview:_contentView];
[_testLabelTaco setText:passDataTest];
NSString *path = [[NSBundle mainBundle] pathForResource:#"statesdata" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
flag = [dict objectForKey:#"StateFlag"];
pop = [dict objectForKey:#"Population"];
yearOfUnion = [dict objectForKey:#"Year"];
area = [dict objectForKey:#"Area"];
city = [dict objectForKey:#"LargeCity"];
abbreviations = [dict objectForKey:#"Abbreviations"];
resNamea = [dict objectForKey:#"ResNames"];
mainViewa = [dict objectForKey:#"MainViewPictures"];
plateViewa = [dict objectForKey:#"LicensePlates"];
_flagView.image = [UIImage imageNamed:[flag objectAtIndex:stateint]];
_populationLabel.text = [pop objectAtIndex:stateint];
_unionYearLabel.text = [yearOfUnion objectAtIndex:stateint];
_areaLabel.text = [area objectAtIndex:stateint];
_cityLabel.text = [city objectAtIndex:stateint];
_abbrLabel.text = [abbreviations objectAtIndex:stateint];
_resNameLabel.text = [resNamea objectAtIndex:stateint];
_mainView.image = [UIImage imageNamed:[mainViewa objectAtIndex:stateint]];
_plateView.image = [UIImage imageNamed:[plateViewa objectAtIndex:stateint]];
// Do any additional setup after loading the view.
}
I am putting in a lot of assumption because what is relevant to your issue here is how the masterView Controller calls the detail view controller and that is not in the code you displayed.
Based on what you showed I am assuming that you are creating a new instance of your detailViewController every time you change the selection - if you are - this is what is causing your overhead.
What you need to do to make your app responsive is to separate the individual setup requirement from - (void) viewDidLoad into another method - And in your MasterViewController call that method and bypass reinitialising the DetailVC instance again. Note this will involve meticulous cleanup and setup but your code avoid a lot of overhead that you would otherwise incur if you keep on recreating [alloc] init] the detail view controller instance all the time - (note - this will also keep the memory requirement down)
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%f", cgvalue);
[scrollView setScrollEnabled:YES];
if ([[UIScreen mainScreen] bounds].size.height == 480) {
[scrollView setContentSize:CGSizeMake(320, 920)];
} else {
[scrollView setContentSize:CGSizeMake(320, 834)];
}
[scrollView addSubview:_contentView];
[self setupDetailVC:self];
}
-(void) setupDetailVC:(ID) sender {
[_testLabelTaco setText:passDataTest];
// Do any additional cleanup and setup after loading the view. }
In your masterViewController: Do this
#synthesize *detailVC; - should have been created in appDelegate code;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[self configureDetailItemForRow:indexPath.row];
}
- (void)configureDetailItemForRow:(NSUInteger)row {
detailVC.property1 = Currentproperty;
detailVC.Utility_sw = NO;
// detailVC.managedObjectContext = managedObjectContext;
[detailVC setupDetailVC:self];
}
One thing you could try is to set the images on a separate thread, using Grand Central Dispatch. This would take the workload off the main thread and your UI shouldn't slow down. You could do something like this:
__weak typeof(self)weakSelf = self; // to avoid a retain cycle
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
__strong typeof(weakSelf)strongSelf = weakSelf;
UIImage * flagImage = [UIImage imageNamed:[strongSelf->flag objectAtIndex:stateint]];
UIImage * mainImage = [UIImage imageNamed:[strongSelf->mainViewa objectAtIndex:stateint]];
UIImage * plateImage = [UIImage imageNamed:[strongSelf->plateViewa objectAtIndex:stateint]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates on main thread
strongSelf->_flagView.image = flagImage;
strongSelf->_mainView.image = mainImage;
strongSelf->_plateView.image = plateImage;
});
});

UIView is not removed from superview

I`m having problem with removing view from superview.
Adding view:
- (void)createCircles
{
NSString *currentDate = [self currentDate];
NSArray *array = [self.horizontalScroll subviews];
UILabel *label = nil;
for (label in array)
{
if ([label.text isEqualToString:currentDate])
{
UIView *view = [[UIView alloc] initWithFrame:label.frame];
view.backgroundColor = [UIColor redColor];
[self.horizontalScroll insertSubview:view atIndex:0];
[self.labelsArray insertObject:view atIndex:0];
}
}
}
Trying to remove:
- (void)labelTouch:(UITapGestureRecognizer*)sender
{
NSArray *array = [self.horizontalScroll subviews];
UILabel *label = (UILabel*)sender.view;
for (int i = 0; i < [array count]; ++i)
{
UILabel *l = array[i];
if (label.tag == l.tag)
{
UIView *view = nil;
view = [self.labelsArray objectAtIndex:0];
view.hidden = YES;
[view removeFromSuperview];
view = nil;
[self.labelsArray removeObjectAtIndex:0];
}
}
}
But after touch view is still displaying. Tried to remove label (l) - it is removed
Try this,
[[[self.horizontalScroll subviews] objectAtIndex:0] removeFromSuperView];
You should store reference to this "unkillable" view in ivar or property. Initialize it in first method and call removeFromSupperView in second.

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

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;
}

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

Resources