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)];
Related
I created a NavigationBar and added it to the UIViewController. But after init, the reference turns to nil. I'm new to iOS and OC, I don't know why. Anyone can help? Thank you.
code summary:
#interface ContainerViewController()
#property (nonatomic, retain) UINavigationBar *nav;
#property (nonatomic, retain) UINavigationItem *navItem;
#end
#implementation ContainerViewController
- (instancetype) initWithParams:(NSDictionary *)params {
self = [super init];
if (self) {//...}
return self;
}
- setNavTitle:(NSDictionary *) params {
NSString *title = params[#"title"];
/////////////////////////////////
// here goes wrong
// self.navItem == nil here, why?
/////////////////////////////////
self.navItem.title = title;
}
- (void) viewWillAppear:(Bool)animated {
[super viewWillAppear:NO];
static float navHeight = 64.0;
UIViewController *wvController = [WebView init here];
UINavigationBar *nav = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), navHeight)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:title];
nav.items = [NSArray arrayWithObjects: navItem, nil];
///////////////////////////////
// I saved the reference here
//////////////////////////////
[self setNav:nav];
[self setNavItem:navItem];
[self.view addSubview:nav];
[self addChildViewController:wvController];
wvController.view.bounds = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - navHeight);
[self.view addSubview:wvController.view];
[wvController didMoveToParentViewController:self];
}
#end
This will be useful for you, kindly check and do
Tutorial point site is very easy to learn some important UI basics if you are working in Objective C
i want to do like on this picture:
i do templateDisplayNode:
#interface TemplateDisplayNode : ASDisplayNode
#property (nonatomic, strong) ASDisplayNode *headerNode;
#property (nonatomic, strong) ASDisplayNode *ContentNode;
- (void)addContentNode:(ASDisplayNode *)contentNode;
#end
#implement TemplateDisplayNode
- (instancetype)init
{
self = [super init];
if (self) {
[self createSubviews];
}
return self;
}
- (void)createSubviews {
[self createHeaderNode];
[self createContentNode];
}
- (void)addContentNode:(ASDisplayNode *)contentNode {
[self.contentNode addSubnode:contentNode];
}
- (void)createHeaderNode {
self.headerNode = [[ASDisplayNode alloc] init];
self.headerNode.backgroundColor = [UIColor blueColor];
[self addSubnode:self.headerNode];
}
- (void)createContentNode {
self.contentNode = [[ASDisplayNode alloc] init];
self.contentNode.style.flexGrow = YES;
[self addSubnode:self.contentNode];
}
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize {
CGFloat mainScreenWidth = [UIScreen mainScreen].bounds.size.width;
NSMutableArray *mainStackContent = [[NSMutableArray alloc] init];
if (self.headerNode) {
self.headerNode.style.preferredSize = CGSizeMake(mainScreenWidth, 48);
[mainStackContent addObject:self.headerNode];
}
if (self.contentNode) {
[mainStackContent addObject:self.contentNode];
}
ASStackLayoutSpec *contentSpec =
[ASStackLayoutSpec
stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
spacing:0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsStretch
children:mainStackContent];
return contentSpec;
}
#end
and create page of TemplateDisplayNode class:
#interface Page1Node : TemplateDisplayNode
#end
#implement Page1Node
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize {
[super layoutSpecThatFits:constrainedSize];
}
#end
And use it in ASViewController:
#interface MyViewController : ASViewController
#property (nonatomic, strong) MyCustomASViewControllerWithTableNode *myTableNodeViewController;
#property (nonatomic, strong) Page1Node *page1node;
#end
#implement MyViewController
- (instancetype)init {
self.page1node = [[Page1Node alloc] init];
self = [super initWithNode:self.page1node];
if (self) {
[self createMyTableNodeViewController];
}
return self;
}
- (void)createMyTableNodeViewController {
self.myTableNodeViewController = [[MyCustomASViewControllerWithTableNode alloc] init];
[self.page1node addContentNode:self.myTableNodeViewController.node]; //add TableNode like content on page1node
[self addChildViewController:self.myTableNodeViewController];
[self.myTableNodeViewController didMoveToParentViewController:self];
}
#end
MyCustomASViewControllerWithTableNode:
#interface MyCustomASViewControllerWithTableNode : ASViewController
#property (nonatomic, strong) ASTableNode *tableNode;
#end
...
- (instancetype)init {
_tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
self = [super initWithNode:_tableNode];
if (self) {
_tableNode.dataSource = self;
_tableNode.delegate = self;
}
return self;
}
and when i run it, I see a table in the content field, but I can not scroll the table, because Size frame ContentNode = {0; 0};
How to make layout correctly in order to set the size? If I do the same thing, but without using TemplateDisplayNode, then everything works. I would like to use TemplateDisplayNode to remove a lot of duplicate code for similar pages.
AsyncDisplayKit documentation is not advised to use:
[super layoutSpecThatFits:constrainedSize];
If I remove this line, then I do not go into layoutSpecThatFits in TemplateDisplayNode.
Advise how to be? What solutions can be?
I have a custom class based on UIButton, and I have difficulties calling the custom setter method in this custom class. I will list the codes in these files:
CallMyMethod.h (subclass of UIButton)
CallMyMethod.m
CallOtherClassMethod.h (to call setter method in CallMyMethod)
CallOtherClassMethod.m
CallMyMethod.h
#interface CallMyMethod : UIButton
#property (nonatomic, setter=setIsSelected:) BOOL isSelected;
#property (nonatomic, retain) UIImageView *checkmarkImageView;
- (void)setIsSelected:(BOOL)aIsSelected; //this is unnecessary, I guess
#end
CallMyMethod.m
#implementation CallMyMethod
#synthesize isSelected = _isSelected;
#synthesize checkmarkImageView = _checkmarkImageView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self loadView];
}
return self;
}
- (void) loadView
{
[self.checkmarkImageView setHidden:YES];
}
- (UIImageView *)checkmarkImageView
{
if (_checkmarkImageView == nil) {
UIImage *checkmarkImage = [UIImage imageNamed:#"checkmark.png"];
_checkmarkImageView = [[UIImageView alloc]initWithImage:checkmarkImage];
[_checkmarkImageView setFrame:CGRectMake(10, 10, 32, 32)];
[self addSubview:_checkmarkImageView];
}
return _checkmarkImageView;
}
- (void)setIsSelected:(BOOL)aIsSelected
{
_isSelected = aIsSelected;
[self.checkmarkImageView setHidden:!_isSelected];
[self addSubview:_checkmarkImageView];
}
#end
CallOtherClassMethod.h
#class CallMyMethod;
#interface CallOtherClassMethod : UIViewController
#property (nonatomic,retain) CallMyMethod *btnCMM;
#end
CallOtherClassMethod.m
#import "CallMyMethod.h"
#implementation CallOtherClassMethod
#synthesize btnCMM;
- (void)viewDidLoad
{
[super viewDidLoad];
self.btnCMM = [[CallMyMethod alloc]initWithFrame:CGRectMake(0, 30, 50, 70)];
//somewhere in my code I will add btnCMM to the view
[someView bringSubviewToFront: btnCMM];
[someView addSubview: btnCMM];
}
//somewhere where I pressed a button to trigger this method
- (IBAction) pressMe:(id)sender
{
NSLog(#"self.btnCMM %#", self.btnCMM); //returned as btnCMM is nil ?!
[self.btnCMM setIsSelected:YES];
}
#end
The issue lies in the program not able to run the codes in setIsSelected method, I have traced btnCMM to be nil in NSLog. I wonder why is this so, because when I call CallOtherClassMethod as a UIViewController, the viewDidLoad would have initialised my custom button. Am I doing something wrong here?
Why not override setSelected, which is a method on UIButton and then use button.selected = YES?
If you want to debug why your button becomes nil, implement dealloc in your UIButton subclass, put a breakpoint there, and see the stack trace to find the reason.
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++;
}
}
}
I've created a view with a variable and loaded it in the loadView method of a view controller. How do I pass a value to the view variable from the view controller after the loadView method has been called?
LocationView.m
#import "LocationView.h"
#implementation LocationView
#synthesize locationTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
locationTitle = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 300, 20)];
[self addSubview:locationTitle];
}
return self;
}
LocationViewController.m
#import "LocationViewController.h"
#import "LocationView.h"
#interface LocationViewController ()
#end
#implementation LocationViewController
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
LocationView *locationView = [[LocationView alloc] initWithFrame:frame];
[self setView:locationView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
How do I pass a value to locationTitle here?
}
You've already set up the locationTitle property for LocationView objects, so you can just access that. The only thing you need to do beforehand is keep a reference to the LocationView object around in an instance variable so you can access it from any instance method.
#implementation LocationViewController {
LocationView *_locationView;
}
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
_locationView = [[LocationView alloc] initWithFrame:frame];
[self setView:_locationView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_locationView.locationTitle = #"Test";
}
#end
Alternatively, since you are assigning the custom view to the view controllers main view, you could cast that:
- (void)viewDidLoad
{
[super viewDidLoad];
((LocationView *)self.view).locationTitle = #"Test";
}