i inherit from UIButton but i found a problem how to initialize it to an UIButtonRoundedRect
i wrote this to initialize my heritated button
-(id)initWithEvent:(NSDictionary*)myEvent{
self=[super init];
self.event=myEvent;//if i use what Erdemus said event is not allocated
return self;
}
the type of button have a readonly property so i can't change it after been initialized
thank you for help.
The answer of Erdemus was not the convenient one , because with his answer self is casted to an UIButton object so objective-c doesn't recognize the attributes of my class.
there is another suggestion?
Related
EDIT: I apologize for wasting time, the erorr had nothing to do with what I'm taking about but rather some logic in my code that made me believe this was the cause. I'm awarding Kevin with the correct answer since using his idea to pass the whole AuthorSelectionView, and his note on correcting the NSNumer mistake. Sorry about that.
I've been trying to figure this out for hours, and even left it alone for a day, and still can not figure it out...
My situation is as follows:
I've created a custom class that implements 'UIView' and made this class into a protocol as follows:
custom UIView h file
#protocol AuthorSelectionViewDelegate <NSObject>
-(void)AuthorSelected:(NSNumber *)sender;
#end
#import <UIKit/UIKit.h>
#interface AuthorSelectionView : UIView
#property (nonatomic,assign) id<AuthorSelectionViewDelegate> delegate;
#property (strong,retain) NSNumber *authorID;
- (id)initWithFrame:(CGRect)frame withImage:(UIImage *)img withLabel:(NSString *)lbl withID:(int)authorID ;
#end
the implementation...
- (id)initWithFrame:(CGRect)frame withImage:(UIImage *)img withLabel:(NSString *)lbl withID:(int)authorID
{
self = [super initWithFrame:frame];
if (self) {
self.authorID = [[NSNumber alloc] initWithInt:authorID]; //used to distinguish multiple instances of this class in a view.
...
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, FRAMEWIDTH, FRAMEHEIGHT)];
[button addTarget:self action:#selector(CUSTOMBUTTONCLICK) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void) CUSTOMBUTTONCLICK
{
[self.delegate performSelector:#selector(AuthorSelected:) withObject:self.authorID];
}
Now the method in my delegate object gets called just fine, but my major problem here is that something is going on with the object being pass through when i have multiple instances of the AuthorSelected class alloc'd.. (the NSNumber authorID). I'm getting some weird behavior with it. It seems almost random with the value being passed, but i'm detecting some pattern where the value passed through is coming up late..
thats confusing so ill try to explain:
I create two instances of the AuthorSelected view, one with authorID=1 and the other with authorID=2.
On the first press, lets say i press the first button, i'll get 1 as expected.
On the second press, if I press the 1st custom button, i'll get '1', but if i press the second i'll still get 1.
On the third go, either button will give me back '2'
I feel like this is some issue with pointers since that has always been a weak point for me, but any help would be greatly appreciated as I can not seem to figure this one out.
Thank you!
EDIT:
as requested here is how I create the AuthorSelectionView Objects...
AuthorSelectionView * asView01 = [[AuthorSelectionView alloc]
initWithFrame:CGRectMake(0, 0, FRAMEWIDTH, FRAMEHEIGHT)
withImage:userPic1
withLabel:randomUserName
withID:1];
asView01.delegate = self;
AuthorSelectionView * asView02 = [[AuthorSelectionView alloc]
initWithFrame:CGRectMake(0, 0, FRAMEWIDTH, FRAMEHEIGHT)
withImage:userPic2
withLabel:randomUserName2
withID:2];
asView02.delegate = self;
A detail that may be important:
As soon as i click on one of these custom views, my code is set to (for now) call the method that runs the above AuthorSelectionView alloc code, so that i can refresh the screen with the same layout, but with different userpic/userName. This is poor design, I know, but for now I just want the basic features to work, and will then worry about redrawing. I metion this tidbit, becuase I understand that objective-c 'layers' veiws on top of eachother like paint on a canvas, and had a thought that maybe when I click what I think may be my 2nd button, its really 'clicking' the layer beneath and pulling incorrect info.
Your description of the problem is a bit confusing, but this line in your init is very clearly wrong:
self.authorID = [self.authorID initWithInt:authorID];
In -init, your property self.authorID defaults to nil, so the expression [self.authorID initWithInt:authorID] is equivalent to [nil initWithInt:authorID], which evaluates back to nil. So you should actually be seeing nil in your action. You probably meant to say self.authorID = [NSNumber numberWithInt:authorID]
You're missing the alloc message, so this message:
self.authorID = [self.authorID initWithInt:authorID];
Is sent to a nil target, because self.authorID hasn't been allocated yet.
So first allocate it, then use the init method, or mix these two messages. A faster syntax allows to do it this way:
self.authorID= #(authorID);
EDIT
I don't see where you initialize the delegate, that method shouldn't even be called if you haven't initialized it. Show the code where you create the AuthorSelectionView objects and set the delegates.
instead of :
self.authorID = [self.authorID initWithInt:authorID];
put :
self.authorID = [NSNumber numberWithInt:authorID];
or
self.authorID = [[NSNumber alloc] initWithInt:authorID];
EDIT :
Don't you have errors or warnings in your code ? I can't see you returning self object in the init method ("return self;")
I have a method that takes a UIButton, modifies its properties and returns a UIButton. However, it doesn't ever seem to be initialized. I'm sure I'm doing something wrong with the memory management here, but don't exactly know how to fix it. No runtime errors occur.
It is called like so...
newGameBtn = [self customButtonFromButton:newGameBtn
withText:[NSString stringWithFormat:#"NEW GAME"]
withFontSize:22
withBorderColor:[UIColor orangeColor]
isSilent:YES];
[dashboardContainer addSubview:newGameBtn];
The method is defined as follows...
- (UIButton*) customButtonFromButton:(UIButton*)button withText:(NSString*)text withFontSize:(int)fontSize withBorderColor:(UIColor*)borderColor isSilent:(BOOL)isSilent {
button = [[[UIButton alloc] init] autorelease];
// Set properties from parameters
// Other conditional custom stuff here
return button;
}
NOTE: newGameBtn is of type UIButton* and is initialized with:
newGameBtn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
Another option might be to subclass UIButton, but I figured I'd try to fix this since I've already walked down this path.
You should use +[UIButton buttonWithType:] when creating buttons to get a properly initialized button.
Most classes are not properly initialized by the default -[NSObject init] method. So please look at the class reference, or superclass reference, for a usable initialization method.
In this case you should also set a frame.
You don't modify this button with your method, you're creating a completely new one with alloc-init!
If you want to change the button in your first argument just remove the first line of your method
Basically if I have a method declared and tied to a button such as:
- (IBAction) clickMe:(id)sender {
.....
}
Is there a way in this method to see whether sender is a subclass of type UIViewController and if so, somehow access something like [sender.view removeFromSuperView] ?
Is this at all possible?
Thanks!
You can use
isKindOfClass:
Returns a Boolean value that indicates
whether the receiver is an instance of
given class or an instance of any
class that inherits from that class.
(required)
to determine if sender is of a certain subclass. After that you should cast sender to UIViewController to remove it's view, else you'll get a warning from the compiler.
Good Evening,
Here is the problem, [self.view addSubview:pauseView];
before the pauseView is loaded over the current view a BOOL isPaused is turned to false and then the subview appears. i am trying to change the value of the variable to false from withing the pauseview but since it's not on the current class i am unable to do this.
I know that this topic is already covered in stackoverflow but i still cannot solve my problem. If i'm able to solve this problem, it will solve the same kind of problem in 3 others apps of mine.
Sincerely,
Sonic555gr
Define isPaused as a property in the class that defines isPaused (let's call it MasterView):
// inside MasterView.h
#property (nonatomic,assign) BOOL isPaused;
Then make your subview pauseView a custom UIView subclass (let's call it PauseView) and in this subclass define a property called master of type MasterView:
// inside PauseView.h
#property (nonatomic,assign) MasterView *master
Then when you alloc/init your pauseView just set this property:
// somewhere inside MasterView.m
PauseView *pauseView = [[PauseView alloc] initWithFrame:frame];
pauseView.master=self;
Finally in your PauseView class, in the point of your code where you want to change the isPaused property, do this:
// somewhere in PauseView.m
master.isPaused=YES
You really should have a think about your architecture and try to move your application logic from away from UIViews and back to the controller (i.e. delegates might be a good option but impossible to know without seeing more of your code and what you are trying to achieve).
If you insist on manipulating the variable from the UIView, you need to pass a reference of your viewController to the pauseView when you initialise it.
So in your PauseView class, you would create a custom initialiser:
-(id)initWithFrame:(CGRect)frame andViewController:(id)vc {
self = [super initWithFrame:frame];
if (self) {
// Any other custom initialisation here
}
}
Any idea from a code design standpoint why does the internal implementation of UITextView uses an NSString but not an NSMutableString when its content is meant to change often?
From a general coding point of view:
When setting a property the property setter method is called. That way the control is able to notice when the property is changed, so that it can redraw the control with the new content.
If the property is a mutable object, you can change its contents and the control will not get any notification that this has happened, so it doesn't know that the control needs to be redrawn.
It's a general pattern in Cocoa to pass around immutable objects instead of allowing outside classes access private mutable variables. You'll see the same thing with collections classes like NSArray and NSDictionary.
Of course, there's no reason you can't change what it points to! Because the member is just a pointer, you can replace the string with an NSMutableString yourself if you want.
This might be a more efficient approach if you want to append a lot of text to the view.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[myTextView setText:[[NSMutableString alloc] init]];
}
return self;
}
Just be sure to still call setText to because as #Guffa explained in his answer, otherwise the view won't know to redraw itself.
- (void)appendText:(NSString*)text
{
NSMutableString *dispText = (NSMutableString*)[myTextView text];
[dispText appendString:text];
[myTextView setText:dispText]; // notify myTextView of text change!
}