Custom UIView getting display late - ios

I'm facing an weird issue, I'm developing a iOS static library, this static library have some custom UIViews. These custom views contains UIButtons and IBOutlets for those buttons, Custom UIView has been create in Xib. Now this static library I'm including inside another static library and I'm attaching custom UIView
of library one in to UIViewController's UIView of static library two with -
[self.view addSubview:aCustomViewFromLibrary1];
So when I'm using Library 2 in to some product everything goes great but when code of adding custom UIView of static library one to static library two runs everything goes right but custom UIView appears late, about half a minutes late.
here is the code for one of the custom UIView in static library one...
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(!self){
return nil;
}
_otpTextField.delegate = self;
loadView()
_approveOtpBtn.layer.cornerRadius = 5;
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
viewFrame = frame;
CALayer *layer = self.layer;
layer.shadowOffset = CGSizeMake(1, 1);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowRadius = 4.0f;
layer.shadowOpacity = 0.80f;
layer.shadowPath = [[UIBezierPath bezierPathWithRect:layer.bounds] CGPath];
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if(!self){
return nil;
}
loadView()
_approveOtpBtn.layer.cornerRadius = 5;
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
return self;
}
-(void) awakeFromNib{
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
_approveOtpBtn.layer.cornerRadius = 5;
}
// Approve OTP
-(IBAction)approveOtp:(UIButton *) aButton{
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
}
// minimize custome browser
-(IBAction)minimizeCB:(UIButton *) aButton{
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
}
- (void) RegenerateOTP:(UIButton *) aButton{
NSLog(#"%#",[NSString stringWithFormat:#"%s", __PRETTY_FUNCTION__]);
}
------UPDATE------
This is how I'm adding above custom View in the UIViewController's UIView.
- (void) updateView{
if([paymentOption isEqualToString:CHOOSE]){
if(_choose){
[_choose removeFromSuperview];
_choose = nil;
}
if(_approveOTP){
[_approveOTP removeFromSuperview];
_approveOTP = nil;
}
if(_regenOTPView){
[_regenOTPView removeFromSuperview];
_regenOTPView = nil;
}
_choose = [[CBAllPaymentOption alloc] initWithFrame:CGRectMake(0,self.resultView.frame.size.height - 227,self.resultView.frame.size.width,227)];
_choose.bankJS = _bankSpecificJavaScriptDict;
_choose.handler = self;
NSLog(#"loadJavascript AllOptionView view = %# ResultView = %#",_choose,_resultView);
//[_resultView addSubview:_choose];
if(_connectionHandlerDelegate && [_connectionHandlerDelegate respondsToSelector:#selector(addViewInResultView:)]){
[_connectionHandlerDelegate addViewInResultView:_choose];
}
[_resultView bringSubviewToFront:_choose];
// view getting display late so call setNeedDisplay.
[_choose setNeedsDisplay];
_choose.isViewOnScreen = YES;
}
}
Any solution and suggestion are welcome

Any changes you make to the UI must be done on the main thread.
You can try something like this.
dispatch_async(dispatch_get_main_queue(), ^{
// perform updates here
});

Related

Present a loading view that blocks touches

I'm trying to add a subview to view that displays an activity indicator and blocks touches while I'm fetching data from the server.
Here is the code that adds the loading view to the main view controller's screen:
+ (void)showLoadingView {
ViewController *vc = [AppDelegate mainViewController];
if (!vc._activityViewContainer) {
LoadingView *loadingView = [[LoadingView alloc] initWithFrame:vc.view.bounds];
[vc.view addSubview:loadingView];
vc._activityViewContainer = loadingView;
}
}
+ (void)stopLoadingView {
ViewController *vc = [AppDelegate mainViewController];
if (vc._activityViewContainer) {
[vc._activityViewContainer removeFromSuperview];
vc._activityViewContainer = nil;
}
}
Here is my loading view:
#implementation LoadingView
- (id)initWithFrame:(CGRect)frame {
if (self == [super initWithFrame:frame]) {
self.userInteractionEnabled = YES;
self.backgroundColor = [UIColor lightGrayColor];
self.alpha = 0.6;
self.layer.zPosition = 10000;
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
NSUInteger avSize = 100;
CGRect activityViewFrame = CGRectMake((frame.size.width - avSize) / 2, (frame.size.height - avSize) / 2, avSize, avSize);
activityView.frame = activityViewFrame;
[self addSubview:activityView];
[activityView startAnimating];
}
return self;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? self : nil; }
#end
I'm trying to make it so that the loading view absorbs/blocks all touches to other sibling views. It's working fine when I'm testing it by presenting it without doing any fetching, it enters the loading view's hitTest method and blocks the touch. However, when I'm actually doing any kind of fetch from the server, it doesn't seem to work. The touch is delayed a few seconds and does not get intercepted by the LoadingView.
I'm using GTMHTTPFetcher's
- (BOOL)beginFetchWithCompletionHandler:(void (^)(NSData *data, NSError *error))handler
I'm not that sure what's going on and I tried looking for similar examples on SO, but couldn't find what I was looking for. Any help would be great, thanks!
I was doing my fetches on the main thread which was blocking the UI; I thought GTM did everything on a different thread, but it doesn't. Thanks to those who posted things which helped me in the right direction

initWithImage works fine initWithFrame is being called more than once

I am sublassing either an UIImageView or UIView for generating simple color tiles with digits. If I am using UIImageView, I use initWithImage method. If I use UIView, the method initWithFrame is being used.
Either red square image or programmatically generated red view is used for initialization.
The problem can be seen on two screenshots: when initWithImage is being used - everything works fine. If initWithFrame method is being used, I am ending with multiple white views without any information created in even order with normal views. All the screenshots and code attached.
This how it looks when initializing using initWithImage:
- (id)initWithImage:(UIImage *)image {
self = [super initWithImage:image];
if (self) {
//Some non-important, label-related stuff.
[self addSubview:self.numberLabel];
}
return self;
}
And this is how it looks with initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.redView = [self redViewWithFrame:frame];
[self addSubview:self.redView];
//label-related stuff
}
return self;
}
- (UIView *)redViewWithFrame:(CGRect)frame {
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor redColor];
view.alpha = 1;
return view;
}
And the for-loop, calling these initializers from another class (UIScrollView subclass). The label value is being set after the view had been initialized.
- (void)setNumberOfBlocks:(NSInteger)numberOfBlocks {
_blocks = [[NSMutableArray alloc] init];
CGSize contentSize;
contentSize.width = BLOCK_WIDTH * (numberOfBlocks);
contentSize.height = BLOCK_HEIGHT;
self.contentSize = contentSize;
for (int i = 0; i < numberOfBlocks; i++) {
CGFloat totalWidth = BLOCK_WIDTH * i;
CGRect frame = CGRectMake(0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
frame.origin.x = totalWidth;
BlockView *view = [[BlockView alloc] initWithImage:[UIImage imageNamed:#"block.png"]];
OR!!!
BlockView *view = [[BlockView alloc] initWithFrame:frame];
view.frame = frame;
NSString *number = [NSString stringWithFormat:#"%ld", (long)i + 1];
view.numberLabel.text = number;
[self addSubview:view];
[_blocks addObject:view];
}
}
Googling gave me the impression that this is very common problem, but I haven't found any solution how to beat this. Moreover, I still do not understand, why numbers are in totally right order, the only problem is view position.
The problem is that you're setting the frame of the red view to the superview's frame instead of its bounds. Since the red view is a subview of the BlockView, its frame needs to be relative to its superview, which you get with bounds (its not clear why you even need the red view, as opposed to setting the background color of the block view to red).
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.redView = [self redViewWithFrame:self.bounds];
[self addSubview:self.redView];
//label-related stuff
}
return self;
}
I think you should set the frame origin to (0,0) in redViewWithFrame in ordre to hâve superposed views

Displaying an alert view similar to UIAlertView

I am trying to create a custom "alert view", nothing too fancy I just want to display a view overtop of the current view just like a UIAlertView.
Now here is the problem...I made the view in a nib file and now I want to alloc/init the view whenever I need to present an alert.Can anyone help me?
This is my attempt to get the view initialized...as of right now this crashes my app when I alloc/init a new alert view.
The app is crashing by telling me the view is not key-value compliant for the outlets.. I definitely have the outlets hooked up properly, unless I have a "File's Owner" thing screwed up.
NSObject 0x14e49800> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key....
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self load];
}
return self;
}
- (void)load {
NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
[self addSubview:[views firstObject]];
}
- (void)awakeFromNib {
[super awakeFromNib];
}
- (id)initWithFrame:(CGRect)frame
{
self = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil][0];
if (self) {
[self addSubview:self.contentView];
self.frame = frame;
}
return self;
}
- (instancetype)initWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
confirmButtonTitle:(NSString *)confirmButtonTitle {
self = [self initWithFrame:CGRectMake(0, 0, 320, 568)];
if (self) {
}
return self;
}
I made this method to present the view, just a simple addSubview...
- (void)showInView:(UIView *)view {
[view addSubview:self];
}
Try disabling autolayout and run the code.
Create a class same as below
#import "MyOverLay.h"
#interface MyOverLay (){
// control declarations
UIActivityIndicatorView *activitySpinner;
UILabel *loadingLabel;
}
#end
#implementation AcuOverLay
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)show:(NSString *)message{
// configurable bits
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.75f;
self.autoresizingMask =UIViewAutoresizingFlexibleHeight;
float labelHeight = 22;
float labelWidth = self.frame.size.width - 20;
// derive the center x and y
float centerX = self.frame.size.width / 2;
float centerY = self.frame.size.height / 2;
// create the activity spinner, center it horizontall and put it 5 points above center x
activitySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activitySpinner.frame = CGRectMake(centerX - (activitySpinner.frame.size.width / 2) , centerY - activitySpinner.frame.size.height - 20, activitySpinner.frame.size.width, activitySpinner.frame.size.height);
activitySpinner.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self addSubview:activitySpinner];
[activitySpinner startAnimating];
// create and configure the "Loading Data" label
loadingLabel = [[UILabel alloc]initWithFrame:CGRectMake(centerX - (labelWidth / 2), centerY + 20 , labelWidth, labelHeight)];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.textColor = [UIColor whiteColor];
loadingLabel.text = message;
loadingLabel.textAlignment = NSTextAlignmentCenter;
loadingLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self addSubview:loadingLabel];
}
- (void)hide{
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
[self removeFromSuperview];
}];
}
#end
then create instance wherever you want
loadingOverlay = [[MyOverLay alloc]initWithFrame:[UIScreen mainScreen].bounds];
loadingOverlay.tag = 999;
[[[UIApplication sharedApplication] keyWindow] addSubview:loadingOverlay];
[loadingOverlay show:#"Saving ..."];

Adding a CALayer sublayer inside of UIView init

I'm trying to add a CALayer as a sublayer in a UIView subclass, but when I add the sublayer inside the init method I get EXC_BAD_ACCESS when I add the view to another view or window.
Init method:
- (id)initWithTitle:(NSString *)title message:(NSString *)message
{
if ((self = [super init]))
{
self.title = title;
self.message = message;
self.alertLayer = [[CALayer alloc] init];
self.layer.cornerRadius = kCORNER_RADIUS;
self.layer.shadowRadius = 3.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(15, 20);
self.layer.shadowOpacity = 1.0;
self.alertLayer.delegate = self;
self.alertLayer.masksToBounds = YES;
self.alertLayer.cornerRadius = kCORNER_RADIUS;
[self.layer addSublayer:self.alertLayer]; // This line of code seems to cause EXC_BAD_ACCESS
}
return self;
}
EXC_BAD_ACCESS is caused after calling [self.view addSubview:alertView] inside a view controller or UIWindow.
You have two layers (self.layer and self.alertLayer) which have the same delegate self, this leads to an infinite recursion in internal method -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] when added this view (self) to the view tree. Therefore you must remove self.alertLayer.delegate = self; to avoid crash. If you need to delegate for alarmLayer you can create distinct object.

iOS: Keyboard freezes on device but works in simulator

Whenever I go to enter text in a subclassed UITextfield on the device, I'll get two or three characters entered and then the app freezes. Can't dismiss the keyboard or touch any tabs. Here's the UITextField subclass:
#implementation OAI_TextField
#synthesize elementID;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
colorManager = [[OAI_ColorManager alloc] init];
fileManager = [[OAI_FileManager alloc] init];
self.font = [UIFont fontWithName:#"Helvetica" size:20.0];
self.textColor = [colorManager setColor:66.0 :66.0 :66.0];
self.borderStyle = UITextBorderStyleRoundedRect;
self.backgroundColor = [UIColor whiteColor];
self.returnKeyType = UIReturnKeyDone;
self.delegate = self;
}
return self;
}
#pragma mark Text Field Delegate Methods
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self resignFirstResponder];
//if project number text field we're going to check and see if the "Project" directory contains the file, if not we'll create it
//get super view
UIView* myParent = self.superview;
//get the subviews
NSArray* mySiblings = myParent.subviews;
//get the label
UILabel* myLabel = [mySiblings objectAtIndex:0];
//get the label text
NSString* myLabelText = myLabel.text;
//check it!
if ([myLabelText isEqualToString:#"Project Number:"]) {
NSString* projectNumberPlist = [NSString stringWithFormat:#"%#.plist", self.text];
NSString* projectNumberPlistPath = [NSString stringWithFormat:#"Projects/%#", projectNumberPlist];
[fileManager createFile:projectNumberPlist:projectNumberPlistPath];
}
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSLog(#"ok");
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I'll get the NSLog call in - (void)textFieldDidBeginEditing:. I do not get any error messages in the console. Not really sure where to begin debugging this. Could someone give me a nudge?
Thanks

Resources