NSAlert not working with NSTextField - objective-c

I have an NSAlert with a NSView accessory view that contains two NSTextField's. I can put the cursor in the NSTextField's but I cannot type in them. Instead, it will type in the last line I was typing on in Xcode. I am using Xcode 6.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSAlert *passRequest = [[NSAlert alloc] init];
[passRequest setMessageText:#"Finder wants to restart. Type your password to allow this."];
[passRequest addButtonWithTitle:#"OK"];
[passRequest addButtonWithTitle:#"Cancel"];
[passRequest setAccessoryView:[InputView inputViewWithUsername:#"James Pickering"]];
NSImage *lockImage = [[NSImage alloc] initWithContentsOfFile:#"LOCK_YOSEMITE.png"];
[passRequest setIcon:lockImage];
[passRequest runModal];
}
I did implement the LSUIElement key, but even before that it wasn't running properly. Otherwise, it's straight out of the box cocoa app.
Here is my code for InputView:
#import "InputView.h"
#interface InputView ()
#property (strong, nonatomic) NSString *username;
#end
#implementation InputView
+ (InputView *)inputViewWithUsername:(NSString *)username {
InputView *view = [[self alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, 321, 52))];
[view setUsername:username];
return view;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSTextField *usernameLabel = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 32, 71, 17))];
[usernameLabel setStringValue:#"Username:"];
[[usernameLabel cell] setBordered:NO];
[[usernameLabel cell] setBezeled:NO];
[usernameLabel setEditable:NO];
[usernameLabel setSelectable:NO];
[usernameLabel setBackgroundColor:[NSColor clearColor]];
[usernameLabel setFont:[NSFont systemFontOfSize:13]];
[self addSubview:usernameLabel];
NSTextField *passwordLabel = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(2, 2, 69, 17))];
[passwordLabel setStringValue:#"Password:"];
[[passwordLabel cell] setBordered:NO];
[[passwordLabel cell] setBezeled:NO];
[passwordLabel setEditable:NO];
[passwordLabel setSelectable:NO];
[passwordLabel setBackgroundColor:[NSColor clearColor]];
[passwordLabel setFont:[NSFont systemFontOfSize:13]];
[self addSubview:passwordLabel];
NSTextField *usernameInput = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(77, 30, 206, 22))];
[usernameInput setStringValue:self.username];
[usernameInput setFont:[NSFont systemFontOfSize:13]];
[self addSubview:usernameInput];
NSTextField *passwordInput = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(77, 0, 206, 22))];
[passwordInput setFont:[NSFont systemFontOfSize:13]];
[self addSubview:passwordInput];
}
#end

I am calling this function in int main.
This is your problem. An alert needs a full application set up and running its event loop. In order for typing to go to it, it will need to be the active application.
You should probably create a normal app from Xcode's template. Start with that. Get things working there. You can present your alert in an action method that's connected to a menu item or a button in a window or whatever. (You could also present in the -applicationDidFinishLaunching: app delegate method, I suppose.)
After you've got that working, if there's some reason you need this to work in an unusual context (e.g. command-line tool), you can work on that.
You are modifying the view hierarchy inside of your -drawRect: method. You must not do this.
First, -drawRect: may be called many times over the life of the view and you would be adding subviews every time it draws. More and more subviews, over and over.
Second, even if you were careful to only add them the first time, -drawRect: is for drawing and not for changing the view hierarchy. (There's -viewWillDraw if you need to make such changes just before drawing, but I don't think that's appropriate for this case, either.)
You can add the subviews in an override of -initWithFrame: instead.
By the way, you should probably use NSMakeRect() instead of NSRectFromCGRect(CGRectMake(...)).

Related

NSTextField doesn't show when I set AttributedString placeholder

I'm trying to customize a little bit my NSTextFields and the first step is to customize the placeholder.
I want to change the placeholder color, and I'm trying it out by this way:
- (void)awakeFromNib {
// Color for placeholder in NSTextField - Color: #cdc9c1
NSColor *placeholderColor = [NSColor colorWithCalibratedRed:0.80f green:0.78f blue:0.75f alpha:1.0f];
NSDictionary *placeholderAttributeDict = [NSDictionary dictionaryWithObject:placeholderColor forKey:NSForegroundColorAttributeName];
NSAttributedString *emailPlaceholderString = [[NSAttributedString alloc] initWithString:#"Email" attributes:placeholderAttributeDict];
// NSAttributedString *passPlaceholderString = [[NSAttributedString alloc] initWithString:#"Password" attributes:placeholderAttributeDict];
// NSTextField Email attributes
[[self emailTextField] setDrawsBackground:NO];
[[self emailTextField] setBordered:NO];
[[[self emailTextField] cell] setPlaceholderAttributedString:emailPlaceholderString];
// NSTextField Password attributes
[[self passTextField] setDrawsBackground:NO];
[[self passTextField] setBordered:NO];
[[[self emailTextField] cell] setPlaceholderString:#"Password"];
}
As you may see, the first placeholder in the first NSTextField is established by an NSAttributedString where i try to specify color. The second placeholder in the second NSTextField is just a NSString.
When i run the application, it only shows the second NSTextField. First one doesn't appear anywhere.
What is happening?
Thanks in advanced.
You are setting the same emailTextField twice...
[[[self emailTextField] cell] setPlaceholderAttributedString:emailPlaceholderString];
[[[self emailTextField] cell] setPlaceholderString:#"Password"];
(Does that fix things or was it just an error in the question?)

UITextView doesn't disappear when removedFromSuperview

I have two UITextViews, self.instructions and self.textView, that are supposed to alternate depending on what the user selects.
I create a self.textView like so:
-(void)createSpaceToWrite
{
[self.instructions removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO]; //This adds a UINavigationBar to the view.
if (!self.textView)
{
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 60, 280, 150)];
}
self.textView.backgroundColor = [UIColor whiteColor];
self.textView.font = [UIFont fontWithName:#"Helvetica Neue" size:14];
self.textView.text = #"";
[self.view addSubview:self.textView];
self.textView.delegate = self;
}
Then I create self.instructions like so:
-(void)haikuInstructions
{
[self.textView removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO];
if (!self.instructions)
{
self.instructions = [[UITextView alloc] initWithFrame:CGRectMake(10, 125, [[UIScreen mainScreen] bounds].size.width - 10, [[UIScreen mainScreen] bounds].size.height)];
}
self.instructions.backgroundColor=[UIColor clearColor];
self.instructions.text = #"Text of instructions";
self.instructions.editable=NO;
[self.view addSubview:self.instructions];
[self resignFirstResponder];
}
The user starts with self.instructions displayed against the background image. Fine.
The user switches. The instruction text disappears, to be replaced by the editable self.textView, a white box. Fine.
The user switches back. The instruction text appears--but the white box is still there, even thought I've removed it from the superview. And not only that, it's still editable and still brings up the keyboard when the user goes to edit it!
What am I doing wrong?
EDIT: Well, I basically scrapped all the code and started the class over from scratch, trying to be cleaner about everything, and I'm no longer having this problem, so it must have been something in some other method that was affecting it. Lesson: haphazard coding is bad!
Why do you need to remove your text views interchangeably? Wouldn't it be better to just "hide" them interchangeably by setting the setHidden property like for example:
[self.textView setHidden: YES];
and additionally try the following also:
[self.textView resignFirstResponder];
[self.textView setEditable: NO];
[self.textView setBackgroundColor: [UIColor clearColor]];
[self.textView setAlpha: 0.0];

UIPopoverController trouble

I'm trying to create a popover with the following code:
//.h
#interface LoginViewController : UIViewController <UIPopoverControllerDelegate>
....
#end
//.m
- (IBAction)popoverTest:(id)sender
{
UIViewController *popoverContent = [[UIViewController alloc] init];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
UILabel *nameLabel = [[UILabel alloc] init]; //edited, fixed UILabel allocation
nameLabel.text = #"Person's name";
[nameLabel sizeToFit];
nameLabel.frame = CGRectMake(10, 10, nameLabel.frame.size.width, nameLabel.frame.size.height);
[myView addSubview:nameLabel];
popoverContent.view = myView;
popoverContent.contentSizeForViewInPopover = CGSizeMake(300, 300);
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
popoverController.delegate = self;
[popoverController presentPopoverFromRect:((UIButton *)sender).frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
NSLog(#"ran all code");
}
I created a UIView, put a label as a subview and then assigned my view to the UIViewController.view. Then I created a popover controller, sized the popover controller, set the delegate and presented it from the button's frame.
I receive a SIGABRT and the app crashes.
Is there something I'm missing?
EDIT: I fixed the UILabel allocation. The problem is always there.
Your code is quite strange.
For example why do you create a view and do you add it to the content view of your popover?
Then, you have to make attention to memory leaks. There a lot of them in your code.
That said, here a simple example for display a UIViewcontroller within a UIPopoverController.
- (IBAction)yourAction:(id)sender
UIButton* senderButton = (UIButton*)sender;
UIViewController* yourController = [[UIViewController alloc] init];
UIPopoverController* pop = [[UIPopoverController alloc] initWithContentViewController:yourController];
pop.delegate = self;
pop.popoverContentSize = CGSizeMake(300, 300);
self.popover = pop;
[pop presentPopoverFromRect:senderButton.bounds inView:senderButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
pop.passthroughViews = nil;
[yourController release];
[pop release];
}
where self.popover is a #property with a retain policy. In this manner in UIPopoverControllerDelegate methods (or wherever you want), you can release your popover and/or dismiss it.
Hope it helps.
P.S. Check the code because I've written by hand.
Edit
Usually when you create a popover, its content view controller is or a custom UIViewController or a UINavigationController (in this case you want to take advantage of its navigation bar).
For example, instead of the simple UIViewController, you could create a custom one
//.h
#interface CustomUIViewController : UIViewController
#end
//.m
#implementation CustomUIViewController
// other code here...
- (void)viewDidLoad
{
// here you are sure that the view has been loaded in memory (alternatively override loadView method), so
UIView* greenView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
green.backgroundColor = [UIColor greenColor];
[self.view addSubview:greenView];
[greenView release];
}
#end
and use it within a a popover
- (IBAction)yourAction:(id)sender
UIButton* senderButton = (UIButton*)sender;
CustomUIViewController* yourController = [[CustomUIViewController alloc] init];
// same as before...
}
solved my issue from this question.
short answer: ARC doesn't retain the UIPopoverController.
i made it an instance variable and works just fine.
The problem seems to be the following:
UILabel *nameLabel;
nameLabel.text = #"Person's name";
nameLabel is uninitialized. It points to random memory, and when calling -setText: through the text-property, your application crashes.
Apart from this, you have a few memory leaks. Remember: If you call alloc, you have to release it somewhere.
(I'm not sure how this works with the new automatic alloc/release).

Cannot release UIView in cocos2d

I've got this sample code I got from somewhere around the web.
My .h file looks like:
#interface PopupWindowString : CCNode <UITextFieldDelegate> {
UIView *landscapeView;
UITextField *username;
}
and my .m file in init method has:
landscapeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
CGAffineTransform tr = landscapeView.transform;
tr = CGAffineTransformRotate(tr, (M_PI * -2.0));
landscapeView.transform = tr;
landscapeView.center = [[CCDirector sharedDirector] openGLView].center;
username = [[UITextField alloc] initWithFrame:CGRectMake(160, 100, 160, 90)];
[username setTextAlignment:UITextAlignmentCenter];
[username setDelegate:self];
[username setPlaceholder:#"New name"];
[username setTextColor:[UIColor colorWithRed:255 green:255 blue:255 alpha:1.0]];
[landscapeView addSubview:username];
[[[CCDirector sharedDirector] openGLView] addSubview:landscapeView];
everything is cool and all but when I close the popup dealloc is not called.
It seems that the retainCount on landscapeView is still 1 after this code:
[username release];
[username removeFromSuperview];
[landscapeView release];
[landscapeView removeFromSuperview];
I have no clue about what to do with it... I don't have any other places I would use landscapeView, it's only in here.
I have tried subclassing UIView to try and figure out where from retain and release are called and here's the list:
Opening the popup:
Retain call from my PopupWindowString init method
Retain from [CALayer layoutSublayers]
Release from CALayerLayoutIfNeeded
Closing the popup: [I hit a CCMenuItemImage]
retain from [__NSArrayM addObject] in [UIView(Hierarchy) subviews]
release from my code [the one I pasted previously]
release from my code [remove from subview]
As you can see one release is missing. I think, when closing the popup, this first retain is caused by me touching the view. However it is never released.
Anyone know how to soleve this one?
Thanks,
Krystian
If you are balancing all of the retains implied or directly called with releases, then your job is done.
Are you sure the object is being leaked? How have you determined that (note that retainCount is never the right answer)?
As written, that code does not appear to leak the landscapeView. Note that if the code that releases it is not in your dealloc, you'll want to set landscapeView to nil to prevent a crash when you [landscapeView release] in dealloc.

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope?

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope ?
or:
How do I add a label or another view in the mainview, outside of the ViewController class, in a different class?
thanks
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
[self.view addSubview:lbl];// <-- this works, but ...
// what is "self" referring to?
// and how can I declare and call from another class?
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanAppDelegate *v = [[calcRomanAppDelegate new] init];
[v.viewController.view addSubview:lbl]; // this compiles, but...
// fails to shows a label on the form
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanViewController *v = [[calcRomanViewController new] init];
[v.view addSubview:lbl]; // this just makes a call back to viewDidLoad... endless loop
}
Well, view is just a property of the UIViewController class. Assuming that you have your UIViewController *controller variable somewhere, you can just use
[controller.view addSubview:subview]
The reason that [v.viewController.view addSubview:lbl]; doesn't work is that v is a new instance of calcRomanAppDelegate. Every application has a shared instance of the app delegate, that can be accessed via [[NSApplication sharedApplication] delegate]. Therefore, your code would become:
calcRomanAppDelegate *v = (calcRomanAppDelegate *)[[NSApplication sharedApplication] delegate];
[v.viewController.view addSubview:lbl]; // this compiles but shows a blank form
Also In the code that you wrote, I will point out that the new method returns an initialized object, so you do not need the extra call to init in [[calcRomanAppDelegate new] init]. Instead of using the new method, I suggest using alloc, which doesn't call the initializer. Obviously that is not the issue in this particular case, but it's an important thing to know.
Not sure what you tried to accomplish.
But let's say you are in the view1 and want to create another view (view2) with your UILabel lbl added to this view2. Here are what you would do:
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)]; //x,y, w h are for your view2
[view addSubview:lbl];
[self.view addSubview:view2]; //self is your current viewcontroller - you add view2 on top of view1
On the other hand if you already have a ViewController class ViewController2.h, ViewController2.m and a ViewController2.xib defined. Here are what you would do:
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[viewController2.view addSubview:lbl];
[self.view addSubview:viewController2.view]; //same as before, you need to add viewController2's view to the current view
Hope this help.