So I have a method that sets an integer: -(void)setcurrentviewfromint:(int)currentint{ It is in a class called MyView. From my viewDidLoad method, I call it, and set it too 1:
currentview is of type int, created in my header file
- (void)viewDidLoad
{
[super viewDidLoad];
MyView *myview = [[MyView alloc]init];
[myview setcurrentviewfromint:1];
}
Then, in MyView.m, I have these classes:
-(void)setcurrentviewfromint:(int)currentint{
currentview = currentint;
NSLog("currentviewis:%d",currentview);
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
NSLog(#"drawRectCalled");
if (currentview == 1) {
NSLog(#"do something here");
}
}
}
But the debugger prints out:
2012-07-18 18:02:44.211 animation[76135:f803] currentviewis:1
2012-07-18 18:02:44.223 animation[76135:f803] drawRectCalled
But doesn't print "do something here". Any ideas why currentview doesn't equal 1?
First, about your question.
What datatype is currentview?
Second, it looks like your NSLog in setcurrentviewfromint: never gets called. If it was called, youd see "currentviewis:1" so make sure that is linking up correctly.
And, I must say, camel-case! Your method names are all lowercase and it's hard to read. :)
The issue is that the MYView you are setting is not the one you are reading currentView from.
In viewDidLoad you are creating a local variable myView and then setting its current view and then this myView becomes a memory leak as nothing points to it.
Assuming that MyView is the class the viewDidLoad is on and that currentview is an int attribute of that class (although the why is the method not setcurrentview:) . I would expect the code to be more like
- (void)viewDidLoad
{
[super viewDidLoad];
[self setcurrentviewfromint:1];
}
Thus setting the current view in itself
And as others state please use the Objective C standard of CamelCase
Related
my didAddSubview is not being called.
This is what I am doing.
In my viewController
- (void)viewDidLoad {
[super viewDidLoad];
SomeView *view = [[SomeView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))];
[self.view addSubview:view];
}
Where my SomeView is a UI view (.h file)
#import <UIKit/UIKit.h>
#interface DyteMeetingView : UIView
#end
in which I have didAddSubview like this
- (void)didAddSubview:(UIView *)subview{
[super didAddSubview:subview];
[self someFunc];
}
I placed debugger in didAddSubview but the debugger never reaches here and hence [self someFunc]; is also not called.
Since didAddSubview is a lifecycle method for UI view, I am also not calling it from anywhere.
Can someone help me in figure out the concept I missed out on/what I could be doing wrong?
PS: I don't have any xib file for UIView.
PS: Intentionally added swift tag as well since there isn't large chunk of code and I am confident that swift developers would be able to understand the question/code and might be able to help me out.
didAddSubview in SomeView will be called when a sub view is added to an instance of SomeView, but that isn't what you are doing here. You are adding a SomeView as a subview of another view.
You want didMoveToSuperview; in this method you can use the superview property of self to identify the view that it moved to.
The didAddSubview will be called in viewController.view, instead of your SomeView, because you using viewController.view.addSubview(subview)
I've a custom view subclass with UIView, in it, I've two buttons with an action, now I want to learn something good, and I don't want to implement a delegate to know which button tapped from other class.
I'm showing my custom view with this method,
CustomView *view = [[CustomView alloc] init];
[view show];
This will show my custom view, with two buttons inside (please assume everything is working fine, I only want to implement block to know which button have been tapped). ^_^
What I've tried for block,
- (void) showViewWithCompletionBlock:(void(^)(CustomViewType type))completion;
and yes, I would able to write like this,
CustomView *view = [[CustomView alloc] init];
[view showViewWithCompletionBlock:^(CustomViewType type) {
}];
but now here's the trouble, I don't know how to call this block (or how I can return CustomViewType) when button tap?
Those two buttons action is like this,
- (void) someAction:(UIButton *)sender {
//sender.tag is a CustomViewType which user choose
}
For a note, CustomViewType is an enum like this,
typedef enum {
CustomViewTypeOption1,
CustomViewTypeOption2,
}CustomViewType;
It's easier to deal with blocks using a typedef:
typedef void(^CustomViewCompletionBlock)(CustomViewType type);
(same thing goes for function pointers).
Now store this block in the custom view, using a private category in the .m file:
#interface CustomView () {
CustomViewCompletionBlock _completionBlock;
}
#end
#implementation CustomView
...
#end
Do whatever is necessary to display the view and store the completion block:
- (void)showViewWithCompletionBlock:(CustomViewCompletionBlock)completion
{
// Do whatever it takes to "display" the view
...
_completionBlock = completion;
}
and then call the completion block as-and-when:
- (IBAction)button1Action:(id)sender
{
// Whatever else this method does
...
if (_completionBlock) {
_completionBlock(CustomViewTypeOption1);
}
}
- (IBAction)button2Action:(id)sender
{
// Whatever else this method does
...
if (_completionBlock) {
_completionBlock(CustomViewTypeOption2);
}
}
Please try below code. when you call compilation . take reference of that compilation and when you want to call that block just use that reference.
in .h
typedef enum {
CustomViewTypeOption1,
CustomViewTypeOption2,
}CustomViewType;
typedef void(^CustomViewCompletionBlock)(CustomViewType type);
#interface CustomView : UIView
{
CustomViewCompletionBlock custVTypeBlock;
}
- (void)showViewWithCompletionBlock:(CustomViewCompletionBlock)completion;
#end
in .m
- (void)showViewWithCompletionBlock:(CustomViewCompletionBlock)completion
{
custVTypeBlock = completion;
//i'm calling this for sample.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self someAction:nil];
});
}
- (void) someAction:(UIButton *)sender {
//sender.tag is a CustomViewType which user choose
// call your compilation with your enum.
if(custVTypeBlock)
custVTypeBlock(0);
}
Maybe this will help you.
Try https://github.com/lavoy/ALActionBlocks
It supports UIControl (UIButton), UIBarButtonItem, and UIGestureRecognizer. It is also supported using CocoaPods.
Calling a block type is just like calling a C method. If you your block variable name is, say, myBlock and if it returns a CustomType, then this will work for you:
CustomType blockReturnedCustomType = myBlock();
I am creating a customView and for example, would like to set the text color of the label and initialise the text of the label.
The initWithFrame is the generic function.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
I have tried initialising the label in the initWithFrame, but it doesn't work. But when I do it in awakeFromNib, it allows me to set the text color but not the text(this value comes from a dictionary)
-(void)awakeFromNib
{
//setting of the label textcolor
}
What would be the correct way to initialise the color and text of labels and other stuff?
Need some suggestions and guidance...
Edit:
-(void)viewDidLoad
{
[self updateViewWithDictionary:dictPassed];
}
Something like this?
What I do in some project's is expose a public method like so:
- (void)updateViewWithDictionary:(NSDictionary *)confDictionary;
In that dictionary I pass the parameters I want, and inside the UIView's subview I update it according to what I want.
Edit 1:
Read wrongly your question, sorry. You have a custom UIView that you would like to be updated when your UIViewController starts, or when you actually use it. So you should have something like this:
#interface MyView : UIView
{
}
- (void)updateViewWithDictionary:(NSDictionary *)confDictionary;
#end
And from your viewDidLoad:
-(void)viewDidLoad
{
[self.customView updateViewWithDictionary:dictPassed];
}
I have some custom appearance properties in my view class (a descendant of UIView). I want to customize the view appearance according to these properties, but I can’t do that inside the initializer, since the values set using [[MyClass appearance] setFoo:…] aren’t in effect at that point:
#interface View : UIView
#property(strong) UIColor *someColor UI_APPEARANCE_SELECTOR;
#end
#implementation View
#synthesize someColor;
// Somewhere in other code before the initializer is called:
// [[View appearance] setSomeColor:[UIColor blackColor]];
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
NSLog(#"%#", someColor); // nil
return self;
}
#end
They are already set in layoutSubviews, but that’s not a good point to perform the view customizations, since some customizations may trigger layoutSubviews again, leading to an endless loop.
So, what’s a good point to perform the customizations? Or is there a way to trigger the code that applies the appearance values?
One possible workaround is to grab the value directly from the proxy:
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
NSLog(#"%#", [[View appearance] someColor); // not nil
return self;
}
Of course this kills the option to vary the appearance according to the view container and is generally ugly. Second option I found is to perform the customizations in the setter:
- (void) setSomeColor: (UIColor*) newColor
{
someColor = newColor;
// do whatever is needed
}
Still I’d rather have some hook that gets called after the appearance properties are set.
Why not wait until
- (void)willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
if (newSuperview) {
... code here ...
}
}
if it's giving you trouble?
I believe UIAppearance properties are applied to a view when it is being added into a view hierarchy. So presumably you could access the set properties in UIView didMoveToSuperview.
Caveat: I am using Swift 2, so not sure about earlier versions of Swift / Objective-C. But I have found that didMoveToSuperview() will not work. The properties are available in layoutSubviews(), but that's not a great place to do anything like this (since it can be called more than once). The best place to access these properties in the lifeCycle of the view I have found is didMoveToWindow().
I would have thought that viewDidLoad would be best if it's a one-time thing. Otherwise, viewWillAppear.
EDIT:
If you want to do it in the view, and not it's controller then I would create a custom init for the view along the lines of:
-(id) initWithFrame:(CGRect) frame andAppearanceColor:(UIColor)theColor;
thereby passing the colour into the view at creation time.
I can't figure out what the problem is here. I have a very simple UIViewController with a very simple viewDidLoad method:
-(void)viewDidLoad {
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
[self.view addSubview:v];
[super viewDidLoad];
}
And my GameView is initialized as follows:
#interface GameView : UIView {
and it simply has a new drawRect method:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
NSLog(#"drawing");
}
In my console, I see "making game view" being printed, but "drawing" never is printed. Why? Why isn't my drawRect method in my custom UIView being called. I'm literally just trying to draw a circle on the screen.
Have you tried specifying the frame in the initialization of the view? Because you are creating a custom UIView, you need to specify the frame for the view before the drawing method is called.
Try changing your viewDidLoad to the following:
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
if (v == nil)
NSLog(#"was not allocated and/or initialized");
[self.view addSubview:v];
if (v.superview == nil)
NSLog(#"was not added to view");
[super viewDidLoad];
let me know what you get.
Check if your view is being displayed. If a view is not currently on screen, drawRect will not be getting called even if you add the view to its superview. A possibility is that your view is blocked by the some other view.
And as far as I know, you don't need to write [super drawRect];
Note that even if viewDidLoad is called on a view controller it doesn't necessarily indicate the view controller's view is displayed on screen. Example: Assume a view controller A has an ivar where a view controller B is stored and view controller A's view is currently displayed. Also assume B is alloced and inited. Now if some method in A causes B's view to be accessed viewDidLoad in B will be called as a result regardless whether it's displayed.
If you're using a CocoaTouch lib or file you may need to override the initWithCoder method instead of viewDidLoad.
Objective-C:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
//Do Stuff Here
}
return self;
}
I had a view that was offscreen, that I would load onscreen and then redraw. However, while cleaning up auto-layout constraints in XCode, it decided my offscreen view should have a frame (0,0,0,0) (x,y,w,h). And with a (0,0) size, the view would never load.
Make sure your NSView has a nonzero frame size, or else drawRect will not be called.