objective c setting an object to a class that is not known - objective-c

I have an array of view controllers (there are more that I have shown):
..
settings = [[settingsSettingTab alloc] initWithNibName:#"settingsTab" bundle:nil];
other = [[otherSettingTab alloc] initWithNibName:#"otherTab" bundle:nil];
..
NSArray *views = [NSArray arrayWithObjects:settings,other, nil];
I then loop through them and assign some details to them before pushing them:
for (int i = 0; i < views.count; i++) {
...
NSString *className = NSStringFromClass([[views objectAtIndex:i] class]);
Class myClass = NSClassFromString(className);
myClass *subView = (myClass*)[views objectAtIndex:i];
[self.scrollView addSubview:subView.view];
}
How can I assign the right class to the *subView. It worked fine when I had only one type of view in my array and then I just used:
settingTab *subView = (settingTab*)[views objectAtIndex:i];
But now I need to check and use the right one. I have googled the question, but I'm not sure of how I would describe it? (dynamic typing? Duck typing?) Any pointers would be really appreciated.
Thanks
EDIT:
Here is the whole code:
NSArray *titles = [NSArray arrayWithObjects: #"Basics", #"Colours", #"Shapes", #"Settings", #"Other", nil];
basics = [[basicsSettingTab alloc] initWithNibName:#"basicsTab" bundle:nil];
colours = [[colorsSettingTab alloc] initWithNibName:#"colorsTab" bundle:nil];
shapes = [[shapesSettingTab alloc] initWithNibName:#"shapesTab" bundle:nil];
settings = [[settingsSettingTab alloc] initWithNibName:#"settingsTab" bundle:nil];
other = [[otherSettingTab alloc] initWithNibName:#"otherTab" bundle:nil];
NSArray *views = [NSArray arrayWithObjects: basics,colours,shapes,settings,other, nil];
for (int i = 0; i < views.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i + 20;
frame.origin.y = 0;
CGFloat newWidth = 280;
CGFloat newHeight = 320;
CGFloat locx = 0;
CGFloat locy = 0;
CGRect panel = CGRectMake(locx, locy, newWidth, newHeight);
frame.size = panel.size;//self.scrollView.frame.size;
//subview.view.backgroundColor = [colors objectAtIndex:i];
NSString *className = NSStringFromClass([[views objectAtIndex:i] class]);
Class myClass = NSClassFromString(className);
myClass *subView = (myClass*)[views objectAtIndex:i];
[subView.view setFrame:frame];
subView.tabTitle.text = [titles objectAtIndex:i];
[subView.view.layer setCornerRadius:5.0f];
[subView.view.layer setMasksToBounds:YES];
subView.delegate = self;
[self.scrollView addSubview:subView.view];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * views.count, self.scrollView.frame.size.height);
pageControl.numberOfPages = views.count;
}

From your edit, we see that you have a property tabTitle on each of your custom view controllers. I would recommend that you create a new UIViewController subclass that implements tabTitle, and use that as the superclass for each of your custom controllers. That way your code only needs to know that they are all a MyTabViewController class (for want of a better class name!). So in your for loop:
MyTabViewController *subview = (MyTabViewController *)[views objectAtIndex:i];
[subview.view setFrame:frame];
[subview.tabTitle setText:[titles objectAtIndex:i]];
// ...
[self.scrollView addSubview:subView.view];
Everything else (view property for example) is defined by UIViewController, from which all your subclasses are descendants.
EDIT
Incidentally, I would be careful about the naming of your objects - your view controllers are not views. In particular, this might cause confusion where you have subview.view. Perhaps more appropriate would be subviewController.view, or even just controller.view?

The properties you are setting are common to all through since they all inherit from UIViewController.
replace:
myClass *subView = (myClass*)[views objectAtIndex:i];
with:
UIViewController *subViewController = (UIViewController *)[views objectAtIndex:i];
Also, do be careful about using the terms "view" and viewController" interchangably. They are not the same thing and can get very confusing/complex when you name things like they are.

If all of them are subclasses of UIViewController, then just use it:
****
frame.size = panel.size;//self.scrollView.frame.size;
//subview.view.backgroundColor = [colors objectAtIndex:i];
UIViewController* subView = (UIViewController*)[views objectAtIndex:i];
[subView.view setFrame:frame];
****
If you are not doing anything special to every view controller, then you just don't need to know exact class of it as long as it is subclass of some known class...
Hope it helps :)

Related

Objective-C loop needed

I need some help on automating this with a loop (as I have 500+ buttons). The code is bellow. Thank you.
MyButton *button1 = [[MyButton alloc] init];
button1.name = #"One";
button1.controller = self;
button1.image = [NSImage imageNamed:button1.name];
_buttonArray = [[NSMutableArray alloc] init];
[arrayController addObject:button1];
MyButton *button2 = [[MyButton alloc] init];
button2.name = #"Two";
button2.controller = self;
button2.image = [NSImage imageNamed:button2.name];
_buttonArray = [[NSMutableArray alloc] init];
[arrayController addObject:button2];
Better to name the buttons with a pattern like: "Button125", etc.
Example code, not tested:
for (int i=1; i<= 500; i++) {
[MyClass createButtonNumber:i]; // Where MyClass is the class name this code is in.
}
+ (MyButton *)createButtonNumber:(int)number {
MyButton *button = [MyButton new];
button.name = [NSString stringWithFormat:#"Button%03i", number];
button.controller = self;
button.image = [NSImage imageNamed: button.name];
[arrayController addObject:button];
return button; // Just incase it is needed.
}
Note: The following code repeated for each button makes no sense and has been left out of the example code.
_buttonArray = [[NSMutableArray alloc] init];
for (NSInteger i = 1; i <= 500; ++i) {
MyButton *button = [[MyButton alloc] init];
button.name = ...; // Needs a method to convert from i to corresponding English words
button.controller = self;
button.image = [NSImage imageNamed:button.name];
[arrayController addObject:button];
}
You need an algorithm to convert from i to English words (e.g 1 to "One", 2 to "Two" etc). This can be done with an NSNumberFormatter with numberStyle set to NSNumberFormatterSpellOutStyle, see this for more info.
You still needs 500+ images named according to the buttons' names.
It's just a guess, but UITableView and UITableViewCell might be what you need. I can think of no sane reason to use 500 UIButtons.

UIScrollView with UIViews not shown

I'm trying to use a UIScrollView with UIViews (to manage them as xib files), for now I have an array where I store the views.
testingView is a UIViewcontroller with his own xib file and testingView2 is also an UIViewcontroller with his own different xib file
- (void) viewDidLoad {
[super viewDidLoad];
_testingView = [[TestingViewController alloc] init];
_testingView2 = [[TestingViewController2 alloc] init];
self.array = [[NSArray alloc] initWithObjects: _testingView.view, _testingView2.view, nil];
for (int i = 0; i < [array count]; i++) {
CGRect frame;
frame.origin.x = self.scrollingView.frame.size.width*i;
frame.origin.y = 0;
frame.size = self.scrollingView.frame.size;
[self.scrollingView addSubView: [self.array objectAtIndex:i]];
}
self.scrollingView.contentSize = CGSizeMake (_scrollingView.frame.size.width*[array count], _scrollingView.frame.size.height);
}
the problem is that he is taking only the first view (even if I switch them) and the second view is not shown, the same with UIImages instead of views is working, can someone explain me why? seems like he is not seeing the second view in the array order...
Why are you calculating the variable "frame" inside the for loop when you are not using it?
In my view you should make the following change to your code.
for (int i = 0; i < [array count]; i++) {
CGRect frame;
frame.origin.x = self.scrollingView.frame.size.width*i;
frame.origin.y = 0;
frame.size = self.scrollingView.frame.size;
**UIView *v=[self.array objectAtIndex:i];**
**v.frame=frame;**
**[self.scrollingView addSubView:v];**
}
Hope it works.
In the for loop, you calculate frame for newly added subview, but you don't set that frame to that subview.
In your loop, add your subview like this for example:
UIView *subview = (UIView *)[array objectAtIndex:i];
subview.frame = frame;
[self.scrollingView addSubView:subview];
You need to set the frame for each of the subviews in the scrolling view. For example, you can set the frame of _testingView2.view to be the offset of x from the _testingView1.view frame width.
_testingView2.view.frame = CGRectOffset(_testingView2.frame, CGRectGetWidth(_testingView1.frame), 0)
There are many ways to calculate the frame. Try to use the methods CGRectWidth, CGRectGetMaxX, etc.

Duplicating UIView

I can't figure out how could I duplicate UIView with its contents. Or is it even possible?
I have made and UIView with a label and a button inside a .xib file. Now I wish to copy this view n times only with different label text.
I'm trying to do this like this, but such way I only get the last object shown. _view1 is IBOutlet just like _view1Label.
NSMutableArray *Info = [[NSMutableArray alloc]initWithCapacity:number.intValue];
for(int i = 0; i != number.intValue; i++)
{
NSString *number = [NSString stringWithFormat:#"Zona%i ",[[NSUserDefaults standardUserDefaults] stringForKey:#"ObjectNumber"].intValue];
NSString *zona = [NSString stringWithFormat:#"%#%i",number, i+1];
NSString *parinkta = [[NSUserDefaults standardUserDefaults] stringForKey:zona];
_view1Label.text = parinkta;
_view1.hidden = false;
CGRect newrect = CGRectMake(_view1.frame.origin.x, _view1.frame.origin.y + (80 * i), _view1.frame.size.width, _view1.frame.size.height);
_view1.frame = newrect;
[Info addObject:_view1];
}
for(int i = 0; i != number.intValue; i++)
{
UIView *add = [Info objectAtIndex:i];
[self.view addSubview:add];
}
I guess you'll get the idea what I am trying to do, maybe my idea of doing this is totaly wrong, so could anyone help me get on the path on this ?
Load the view multiple times from the nib, adjusting the label contents on each copy you load. This is much easier, shorter, less prone to error than trying to copy the UIView contents in-memory which you're trying to do.
Here's an example of using UINib to access the nib contents:
UINib *nib = [UINib nibWithNibName:#"nibName" bundle:nil];
NSArray *nibContents = [nib instantiateWithOwner:nil options:nil];
// Now nibContents contains the top level items from the nib.
// So a solitary top level UIView will be accessible
// as [nibContents objectAtIndex:0]
UIView *view = (UIView *)[nibContents objectAtIndex:0];
// assumes you've set the tag of your label to '1' in interface builder
UILabel *label = (UILabel *)[view viewWithTag:1];
label.text = #"My new text";
So just repeat the above code for each nib instance you want.
if you wish to show n views then you have to create the view n times, inside the first for loop, you can not place a single view in multiple places
If you are created the first view through code then you can use the following method.
Change your for loop like:
for(int i = 0; i != number.intValue; i++)
{
NSString *number = [NSString stringWithFormat:#"Zona%i ",[[NSUserDefaults standardUserDefaults] stringForKey:#"ObjectNumber"].intValue];
NSString *zona = [NSString stringWithFormat:#"%#%i",number, i+1];
NSString *parinkta = [[NSUserDefaults standardUserDefaults] stringForKey:zona];
UIView *tempView = [[UIView alloc] init];
UILabel *tempLabel = [[UILabel alloc] init];
tempLabel.frame = _view1Label.frame;
tempLabel.text = _view1Label.text;
[tempView addSubview: tempLabel];
tempView.frame = _view1.frame;
_view1Label.text = parinkta;
_view1.hidden = false;
CGRect newrect = CGRectMake(_view1.frame.origin.x, _view1.frame.origin.y + (80 * i), _view1.frame.size.width, _view1.frame.size.height);
_view1.frame = newrect;
[Info addObject:tempView];
}

Finding Color of a UIView Object and change the Color

Hello Guys actually i have a lot of UIView custom class objects as a subview of a UIViewController class view which is inside a UIScrollView. And i want to check colors of UIView custom class objects. code i use is given below:-
- (void) RectColorCheck:(id)sender
{
NSArray *subViews = [[NSArray alloc] init];
subViews = [self.scrollView subviews];
NSLog(#"array----%#",subViews);
for (viewCG in subViews)
{
if ([viewCG.backgroundColor isEqual: [UIColor darkGrayColor]])
{
[viewCG setBackgroundColor:[UIColor orangeColor]];
}
}
}
but it not works the subview array of viewCG is null.
And the below code which adds the custom class(UIView) objects in viewCG subviews:-
for (int i=0; i<[mapDataArr count]; i++)
{
X = [[[mapDataArr objectAtIndex:i] valueForKey:#"X"] intValue];
Y = [[[mapDataArr objectAtIndex:i] valueForKey:#"Y"] intValue];
W = [[[mapDataArr objectAtIndex:i] valueForKey:#"W"] intValue];
H = [[[mapDataArr objectAtIndex:i] valueForKey:#"H"] intValue];
circleVwObj = [[CircleView alloc] init];
circleVwObj.frame = CGRectMake(X,Y, W, H);
circleVwObj.tag = i;
circleVwObj.lbl.frame = CGRectMake(2,2, circleVwObj.frame.size.width, circleVwObj.frame.size.height/2);
circleVwObj.lbl.text = [[mapDataArr objectAtIndex:i] valueForKey:#"standId"];
NSLog(#"lbl text---%#", circleVwObj.lbl.text);
circleVwObj.lbl.font = [UIFont boldSystemFontOfSize:11];
circleVwObj.lbl.backgroundColor = [UIColor clearColor];
circleVwObj.lbl.textColor = [UIColor whiteColor];
circleVwObj.lbl.textAlignment = UITextAlignmentCenter;
circleVwObj.lbl.minimumFontSize = 11;
circleVwObj.lbl.adjustsFontSizeToFitWidth = YES;
circleVwObj.lbl.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.viewCG addSubview:circleVwObj];
}
If the subviews array is nil, it is very likely that self.viewCG is nil as well and hasn't been initialized.
Also, you should use isEqual: to compare colors. The == operator just compares pointer identity (which might actually give you the expected result in this particular case, but it's likely to break).

Activity Indicator while loading images inside UIScrollView

I have UIScrollView that contains images from the server.
I should put Activity Indicator while the image is currently loading.
UIScrollView contains dynamic number of images from the server.
May I know how can I add activity indicators on each page while the image is loading and remove once image is loaded.
Here's my code to retrieve images:
NSDictionary *items = [NSDictionary dictionaryWithObject:dictInfo forKey:#"images"];
imageList = [items objectForKey:#"images"];
NSArray *img = [imageList objectForKey:#"list"];
NSInteger imgCount = [img count];
buttonArray = [[NSMutableArray alloc] init];
for (int i=0; i<imgCount; i++) {
NSDictionary *imgDict = [img objectAtIndex:i];
// REQUEST FOR IMAGES
NSString *imgPath = [imgDict objectForKey:#"image_slot"];
NSString *imgURL = imgPath;
__block ASIHTTPRequest *requestImage = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:imgURL]];
[requestImage setCompletionBlock:^{
imgView = [UIImage imageWithData:[requestImage responseData]];
if (imgURL.length) {
[pendingRequests removeObjectForKey:imgURL];
}
scrollView.userInteractionEnabled = YES;
scrollView.exclusiveTouch = YES;
scrollView.canCancelContentTouches = YES;
scrollView.delaysContentTouches = YES;
scrollView.bounces = NO;
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
SWTUIButton *imgBtn = [[SWTUIButton alloc] initWithFrame:frame];
imgBtn.url = [requestImage.userInfo objectForKey:#"rURL"];
[imgBtn setImage:imgView forState:UIControlStateNormal];
imgBtn.backgroundColor = [UIColor clearColor];
[imgBtn addTarget:self action:#selector(buttonpushed:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:imgBtn];
[buttonArray addObject:imgBtn];
[imgBtn release];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * img.count, self.scrollView.frame.size.height);
}];
I highly suggest you use NINetworkImageView from https://github.com/jverkoey/nimbus project.
It's very light and useful.
It has a delegate method to let you know when an image is loaded.
What you basically need to do is:
1. create an NINetworkImageView for each page, just like you do with UIImageView, and call set
NINetworkImageView* networkImageView = [[[NINetworkImageView alloc] initWithImage:initialImage]
autorelease];
networkImageView.delegate = self;
networkImageView.contentMode = UIViewContentModeCenter;
[networkImageView setPathToNetworkImage:
#"http://farm3.static.flickr.com/2484/3929945380_deef6f4962_z.jpg"
forDisplaySize: CGSizeMake(kImageDimensions, kImageDimensions)];
https://github.com/jverkoey/nimbus/tree/master/examples/photos/NetworkPhotoAlbums
the add the indicator to the networkImageView as a subview.
implement the delegate as follows:
-(void)networkImageView:(NINetworkImageView *)imageView didLoadImage:(UIImage *)image {
[imageView removeAllSubviews];
}
the end result would be a much smaller code for doing the same thing.