iOS: Dereferencing NSMutableArray - ios

When someone votes down the question... kindly please also comment why you had voted it down.
I have a UIView (myHolderView) on which I want to place 9 or more other views.
I added some UIView (MyView) instances to an NSMutableArray of 9 elements (MyArray).
MyView has a label (UILabel) on it. Can someone please assist how to get label's text using MyArray?
Note:
I am seeing the UIViews added to main holder view and getting labels on it.
initWithFrame:(v,v,v,v) number: (value) is the init method I had overloaded init with.
//These two are declared as global variable
NSMutableArray *tiles;
MyView *tile;
#implementation ViewController
#synthesize myHolderView;
- (void)viewDidLoad
{
[super viewDidLoad];
tiles=[[NSMutableArray alloc]initWithCapacity:9];
for (int xIndex=0; xIndex<3; xIndex++)
{
for(int yIndex=0; yIndex<3; yIndex++)
{
static int label=0;
[tiles addObject:[[MyView alloc]initWithFrame:CGRectMake(value,value,value,value)
number:[[NSString alloc] initWithFormat:#"%d",label+1]]];
[self.myHolderView addSubview:tiles[label]];
//Now - when I want to print the labels onto Console as NSLog messages
//it is printing null
MyView *n=[[MyView alloc]init];
n=(MyView *)[tiles objectAtIndex:label++];
NSLog(#"%#---", n.myLabel.text);
//this also does not work. Definitely wrong dereferencing
// NSLog(#"%#---", (MyView*) [tiles ObjectAtIndex:1].mylabel.text);
//label++;
}
}
}
Please help
how to dereference NSMuableArray objects to the type what we want (the
type we know it exactly)
MyView:
- (id)initWithFrame:(CGRect)frame number:(NSString *)num;
{
self = [super initWithFrame:frame];
if (self) {
MyView *tile = [[[NSBundle mainBundle] loadNibNamed:#"XView" owner:self options:nil] objectAtIndex:0];
tile.myLabel.text=num;
[self addSubview:tile];
}
return self;
}

According to your comment, you want to add some view to your holderview. Later, you want to change text in particular view. So I suggest some way. I think, It will help you..
1) create and Add subview to your holder view
for (int xIndex=0; xIndex<9; xIndex++)
{
MyView *subView = [[MyView alloc]initWithFrame:CGRectMake(value,value,value,value)
number:[[NSString alloc] initWithFormat:#"%d",somecount+1]]]; // doesn't know why do you try this..
subView.tag = xIndex;
[self.myHolderView addSubview: subView];
}
2) Get particular subview with tag value.(No need to maintain any other array in your view controller)
After some time, you want to change text in particular view. Just try it..
MyView *subView = [self.myHolderView viewWithTag:index]; // as like, you access array
subView.myLabel.text = yourUpdateText;

#import "ViewController.h"
#interface MyView : UIView
#property UILabel *myLabel;
- (id) initWithFrame: (CGRect) rect number: (NSString *) string;
#end
#implementation MyView
- (id) initWithFrame: (CGRect) frame number: (NSString *) number {
self = [super initWithFrame:frame];
if (!self) return nil;
// Any things here
// Are you initialized label?
_myLabel = [UILabel new];
[_myLabel setText:number];
[self addSubview:_myLabel];
return self;
}
#end
#interface ViewController ()
#property UIView *myHolderView;
#end
NSMutableArray *tiles;
MyView *tile;
#implementation ViewController
#synthesize myHolderView;
- (void)viewDidLoad {
[super viewDidLoad];
tiles=[[NSMutableArray alloc]initWithCapacity:9];
int value = 1, label = 0;
myHolderView = [UIView new];
for (int xIndex=0; xIndex<3; xIndex++) {
for(int yIndex=0; yIndex<3; yIndex++) {
NSString *number = [[NSString alloc] initWithFormat:#"%d",label+1];
MyView *myView = [[MyView alloc]initWithFrame:CGRectMake(value,value,value,value)
number:number];
[tiles addObject:myView];
[self.myHolderView addSubview:tiles[label]];
//Now - when I want to print the labels onto Console as NSLog messages
//it is printing number
MyView *n=(MyView *)[tiles objectAtIndex:label++];
NSLog(#"%#---", n.myLabel.text);
}
}
// And without tiles array
for (UIView *subView in [myHolderView subviews])
for (UIView *subSubView in [subView subviews])
if ([subSubView isKindOfClass:[UILabel class]])
NSLog(#"%#", [(UILabel *) subSubView text]);
}
#end

Your problem is nothing to do with arrays or dereferencing. It's a logical issue because you are creating multiple views and nesting them.
Change the implementation of MyView:
- (id)initWithFrame:(CGRect)frame number:(NSString *)num;
{
self = [[[NSBundle mainBundle] loadNibNamed:#"XView" owner:self options:nil] objectAtIndex:0];
self.frame = frame;
self.myLabel.text = num;
return self;
}
Try something like this (typed inline so watch for issues):
- (void)viewDidLoad
{
[super viewDidLoad];
tiles = [[NSMutableArray alloc] initWithCapacity:9];
NSUInteger counter = 0;
for (int xIndex=0; xIndex<3; xIndex++)
{
for(int yIndex=0; yIndex<3; yIndex++)
{
MyView *newView = [[MyView alloc] initWithFrame:CGRectMake(value,value,value,value) number:[[NSString alloc] initWithFormat:#"%d", counter+1]]];
[self.myHolderView addSubview:newView];
[tiles addObject:newView];
MyView *logView = (MyView *)[tiles objectAtIndex:counter];
NSLog(#"view %d is %#---", counter, logView.myLabel.text);
counter++;
}
}
}

Related

Custom Class compiled before ViewController

I need a little help about my code. I want to create a custom bar graph. I did all the coding. When I create the objects in my custom class view it works like a charm. However, I want to make it generic. I would like to create it in ViewController. I also add a view in storyboard and change the class name to my custom class name.
It doesn't work when I try like this.
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
GCBarGraphRow *first = [[GCBarGraphRow alloc]init];
first.backgroundColor = [UIColor redColor];
first.value = 20;
GCBarGraphRow *second = [[GCBarGraphRow alloc]init];
second.backgroundColor = [UIColor brownColor];
second.value = 40;
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[first,second];
NSLog(#"View Controller %#",container.values);
self.myGraph.array = container;
}
But when I try to create it in my custom view class it works.
#implementation GCBarGraphView
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
barNumber = [array.values count];
//NSLog(#"%#",array.values);
showDifference = NO;
showShadow = NO;
gradientColor = NO;
drawBaseLine = YES;
[self baseClassInit];
}
return self;
}
-(void)baseClassInit {
GCBarGraphRow *first = [[GCBarGraphRow alloc]init];
first.backgroundColor = [UIColor redColor];
first.value = 20;
GCBarGraphRow *second = [[GCBarGraphRow alloc]init];
second.backgroundColor = [UIColor brownColor];
second.value = 40;
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[first,second];
}
If you're creating a view in the storyboard and assign it's class to your CGBarGraphRow, you also need to create an outlet to your view controller.
Then you don't have to initialize it manually from the view controller code. Your constructor initWithCoder will be called automatically.
Update:
Try this. In the storyboard create the following:
- UIView with proper frame and assign custom class to CGBarGraphView
- Insert into that view two more and assign their classes to GCBarGraphRow
In your CGBarGraphView class create two outlets and bind them to the proper views in the storyboard:
#property (nonatomic, weak) IBOutlet GCBarGraphRow *row1;
#property (nonatomic, weak) IBOutlet GCBarGraphRow *row2;
Remove the code you have above for the view controller - it's not needed. Leave something like that in the CGBarGraphView code:
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
}
return self;
}
-(void)viewDidLoad {
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[self.row1,self.row2];
... whatever else you need to initialize
}

Passing variable From UIViewController to UIView

I have tried modify my code many times, but still can't pass variable from UIViewController to UIView, variable always return (null).
// BPGraphView.h
#interface BPGraphView : UIView
#property (nonatomic, retain) NSString *test;
#end
// BPGraphView.m
#import "BPGraphView.h"
#implementation BPGraphView
#synthesize test;
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
NSLog(#"test %#",test);
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"draw %#", test); // always return (null)
if ([test isEqual:#"something"]) {
[self drawOutLine];
}
}
#end
// BloodPressureViewController.m
- (void)viewDidLoad
{
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"something";
}
In your code:
- (void)viewDidLoad
{
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"dd";
}
The variable graphview is basically destroyed once the viewDidLoad is run to finish. It will never get a chance to run drawRect.
Now the question is how should you define a instance variable of BPGraphView in your UIViewController. The easiest way should be adding a BPGraphView onto your view's xib file and link to an IBOutlet in your UIViewController. In this way, you should be able to assign to test
#IBOutlet BPGraphView graphview;
- (void)viewDidLoad
{
graphview.test = #"dd";
}
Without setting a frame, drawRect will not be called.
BPGraphView * graphview=[[BPGraphView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
graphview.test = #"something";
[self.view addSubview:graphview];
I tried this,it works well,in your code,drawRect is not called
BPGraphView * graphview=[[BPGraphView alloc] init];
graphview.test = #"dd";
[graphview drawRect:CGRectMake(0, 0, 0, 0)];

Multiple instance UIView only load xib file in the first instance

I'm working on as slideshow with some CustomUIView showed in a UIScrollView and it works good. But i have a custom UIView to show the content of each news. My slide works goods , but the XIB file of my custom view is loaded only for the first one and other customview are empty.
Here is my code :
my ViewController.m
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
int nbrNews = _sharedDataManager.rssfeeds.count;
_sliderView.contentSize = CGSizeMake(self.view.frame.size.width*nbrNews, self.view.frame.size.height);
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = nbrNews;
for (int i = 0; i< nbrNews; i++) {
NewsView *newsView = [[NewsView alloc] initWithFrame:CGRectMake(i*self.view.frame.size.width, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSDictionary *news = [_sharedDataManager.rssfeeds objectAtIndex:i];
newsView.titleLabel.text = [news objectForKey:#"title"];
[_sliderView addSubview:newsView];
}
}
CustomView.h
#import <UIKit/UIKit.h>
#interface NewsView : UIView
#property (weak, nonatomic) IBOutlet UILabel *titleLabel;
#end
CustomView.m
#import "NewsView.h"
#implementation NewsView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self = [[[NSBundle mainBundle] loadNibNamed:#"OneNewsView" owner:self options:nil] objectAtIndex:0];
}
return self;
}
#end
here the result :
EDITED : i change the color of the view in my custom view. and we can see that only the first one is realy loaded with xib file. and i dont know why !!!! can you help me?
i solve my problem by adding :
self.frame = frame;
to my customView.m initWithFrame

UnEven Behaviour of UIView when setHidden

I've created 5 UIView dynamically, which consists of one UILabel and one UIButton each. When I click button, the UIView will setHidden. But it works only on one not other four uiviews.
#interface ViewController : UIViewController
{
NSMutableArray *newViews;
}
#property(nonatomic,retain)IBOutlet UILabel *welcome;
#property(nonatomic,retain)CustomView *custom;
-(void)buttonPressed:(UIButton *)sender;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *name=#"string of length";
int length=[name length];
newViews = [NSMutableArray array];
NSMutableArray *myArray = [NSMutableArray arrayWithObjects:#"cricket", #"golf",#"wrestling", #"FootBall is good game", nil];
int yAxis=44;
int lengthOfArray=[myArray count];
for(int a=0; a<=lengthOfArray; a++){
self.custom= [[CustomView alloc]initWithFrame:CGRectMake(20, yAxis, 100, 44)];
yAxis=yAxis+50;
NSLog(#"yaxis is %i",yAxis);
self.custom.tag=200+a;
[newViews addObject:self.custom];
self.custom.Label = [[UILabel alloc]initWithFrame:CGRectMake(5,5, length+70, 30)];
self.custom.button=[[UIButton alloc]initWithFrame:CGRectMake(85,10,12,10)];
UIImage *btnImage = [UIImage imageNamed:#"button_droparrow.png"];
[self.custom.button setImage:btnImage forState:UIControlStateNormal];
[self.custom.button addTarget:self action:#selector(buttonPressed:)forControlEvents:UIControlEventTouchDown];
self.custom.button.tag=self.custom.button.tag+a;
self.custom.backgroundColor=[UIColor greenColor];
custom.Label.text=#"welcome";
custom.Label.backgroundColor = [UIColor yellowColor];
[self.custom addSubview:self.custom.button];
[self.custom addSubview:custom.Label];
[self.view addSubview:self.custom];
}
[self.custom.button addTarget:self action:#selector(buttonPressed:)forControlEvents:UIControlEventTouchDown];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)buttonPressed:(UIButton *)sender
{
[self.custom setHidden:YES];
}
#end
Kindly help me. I am new in iOS development. I need here to create UIView with differrnt reference and that reference assign to UIButton to close that particular UIView but I could not get result out.
You could use UISegmentedControl along with number of xib for each UIView.
In each UIView you can place the required UIControls and link the same.
In the delegate method of SegmentedControl 'indexDidChangeForSegmentedControl:(UISegmentedControl *)sender' on each index remove the earlier UIView and add the required UIView.
In the main header file add the IBOutlet for each UIView
#property (nonatomic, weak) IBOutlet UIView *view1;
#property (nonatomic, weak) IBOutlet UIView *view2;
In .m file in the delegate method 'indexDidChangeForSegmentedControl'
- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {
NSUInteger index = sender.selectedSegmentIndex;
if (UISegmentedControlNoSegment != index) {
if (currentIndex == index) {
return;
}
currentIndex = index;
switch (index) {
case 0:
{
[self.previousView removeFromSuperview];
[self.view addSubview:view1];
self.previousView = view1;
}
break;
case 1:
{
[self.previousView removeFromSuperview];
[self.view addSubview:view2];
self.previousView = view2;
}
break;
}
}
}
Hope this helps.
If you want to use properties, you will have to make a property for each view. Instead, if you want to create them dynamicaly you could store the references to each view in an array.
The next you should know/do is to add a tag to each button. A tag is just a number, which in this case should reference to its position in the Array.
Then based on the button tag (that you can retrieve from the sender) you can retrieve the proper view/button from the array and change the Hidden property on it.
For example (pseudo code/this wont compile):
Creating the views array
#property (nonatomic, strong) NSMutableArray *views;
In View did load create the views
views = [[NSMutableArray alloc] init];
int nrOfViews = 5;
for(int a=0; a<=nrOfViews; a++){
UIView *view = create UIView here.
UIButton *button = create button here.
[view addSubView: button];
[button setTag: a];
[views addObject: view];
}
reference to the view through the pointer retained in the array, find the right one based on the button tag.
-(void)buttonPressed:(UIButton *)sender
{
UIView *view = [views objectAtIndex: sender.tag]; //using the button tag to identify the right view.
[view setHidden: yes];
}
Try something like this:
- (void) buttonPressed: (UIButton*) sender
{
UIView* view = sender.superview;
view.hidden = YES;
}
You need to make some changes as follows
#property(nonatomic,strong)IBOutlet UILabel *welcome; // new arc code
#property(nonatomic,strong)UIView *custom; // new arc code
self.custom = [[UIView alloc]initWithFrame:CGRectMake(20, yAxis, 100, 44)];

UIButton action is not firing from my own class

I have a class which is generating UIButtons dynamically and I want to keep the selector action in the same class as method to make it generic. When I click on the button it crashing. Bellow is my code
RB_RadioButton.h
#import <Foundation/Foundation.h>
#interface RB_RadioButton : NSObject {
NSMutableArray *options;
}
-(id)initWithOptions:(NSArray *)options;
-(void)renderRadioButtons:(UIView *)view initialXPos:(int)initialXPos initialYPos:(int)initialYPos height:(int)height width:(int)width spacing:(int)spacing;
#end
RB_RadioButton.m
#import "RB_RadioButton.h"
#implementation RB_RadioButton {
NSMutableArray *buttonArray;
}
-(id)initWithOptions:(NSArray *)optionsArray {
if(self = [super init]){
options = [[NSMutableArray alloc]initWithArray:optionsArray];
}
return self;
}
-(void)renderRadioButtons:(UIView *)view initialXPos:(int)initialXPos initialYPos:(int)initialYPos height:(int)height width:(int)width spacing:(int)spacing {
buttonArray = [[NSMutableArray alloc]init];
int xpos = initialXPos, ypos = initialYPos;
for (int i = 0; i < options.count; i++) {
UIButton *radio = [[UIButton alloc]initWithFrame:CGRectMake(xpos, ypos, height, width)];
radio.backgroundColor = [UIColor grayColor];
[radio setTag:i];
[radio addTarget:[RB_RadioButton class] action:#selector(actionTap) forControlEvents:UIControlEventTouchUpInside];
UILabel *l = [[UILabel alloc]initWithFrame:CGRectMake(xpos+30, ypos, height, width)];
l.text = [options objectAtIndex:i];
ypos = ypos + height + spacing;
[view addSubview:l];
[view addSubview:radio];
}
}
-(void)actionTap{
NSLog(#"lll");
}
#end
viewController.m
#import "RB_ViewController.h"
#import "RB_RadioButton.h"
#interface RB_ViewController ()
#end
#implementation RB_ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *arr = [[NSArray alloc]initWithObjects:#"a",#"b",#"c", nil];
RB_RadioButton *rd = [[RB_RadioButton alloc]initWithOptions:arr];
[rd renderRadioButtons:self.view initialXPos:20 initialYPos:20 height:20 width:20 spacing:10];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Above code is crashing without any message in debug console.
Please help !
Thanks
Whenever you write this line of code it'l take class method so define actionTap as class method then it'l works like below.
[radio addTarget:[RB_RadioButton class] action:#selector(actionTap) forControlEvents:UIControlEventTouchUpInside];
+(void)actionTap{
NSLog(#"lll");
}
What is that:
[radio addTarget:[RB_RadioButton class] action:#selector(actionTap) forControlEvents:UIControlEventTouchUpInside];
actionTap is normal method which requires self pointer but you are trying to invoke it on Class object!
This line should look like this:
[radio addTarget: self action:#selector(actionTap) forControlEvents:UIControlEventTouchUpInside];
To make it work you have to fix also memory management. Controller should remember your RB_RadioButton object as a filed and release it in dealloc method.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *arr = [NSArray arrayWithObjects: #"a",#"b",#"c", nil]; // here also you had a memory leak
rd = [[RB_RadioButton alloc]initWithOptions:arr]; // rd is object field
[rd renderRadioButtons:self.view initialXPos:20 initialYPos:20 height:20 width:20 spacing:10];
}
- (void)dealloc {
[rd release];
[super dealloc];
}

Resources