I am creating a simple drawing app with a custom view that draws lines on the screen. I am calling a method in my custom view .m file from my viewcontroller file. I've got it set up so it autocompletes my method, which means that it knows it exists, but isn't firing.
In my custom View BezierSigCapView.m
- (void)erase {
path = [UIBezierPath bezierPath];
[pointsArray removeAllObjects];
[self setNeedsDisplay];
NSLog(#"ERASE!");
}
In my View Controller.h file
#property (weak, nonatomic) BezierSigCapView *myView;
In my View Controller.m file
/// in viewDidLoad
BezierSigCapView *theView = [[BezierSigCapView alloc] init];
self.myView = theView;
/// my button code
- (IBAction)ClearButton:(UIBarButtonItem *)sender {
[self.myView erase];
NSLog(#"Should Erase");
}
Kindly check if you have connected the - (IBAction)ClearButton:(UIBarButtonItem *)sender;
to the button.
#hermann pointed me in the right direction. I was creating the view programmatically and in interface builder. I deleted the view that I created programmatically and hooked up an Outlet to the view on interface builder as a property. I also got rid of "theView" which was redundant.
//In view controller.h file
#property (strong, nonatomic) IBOutlet BezierSigCapView *myView;
//In view controller.m file
//in the implementation
#synthesize myView;
//I also removed the code below from the view controller.m file that was causing another issue
self.myView = [[BezierSigCapView alloc] init];
Related
I'm showing an NSPopover in an NSView, originating from a point on an NSBezierPath. I'm able to show the popover without a problem, but I can't seem to set the string value of the two text fields in it. The popover and the content view are both a custom subclass of NSPopover and NSViewController, respectively. The NSPopover subclass is also the NSPopover's delegate, although I don't implement any delegate methods, so I'm not sure I even need to do that.
Here is my subclass of NSViewController:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverViewController : NSViewController
#end
#import "WeightPopoverViewController.h"
#interface WeightPopoverViewController ()
#end
#implementation WeightPopoverViewController
- (id)init {
self = [super initWithNibName:#"WeightPopoverViewController" bundle:nil];
if (self) {
}
return self;
}
#end
And my subclass of NSPopover:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverController : NSPopover <NSPopoverDelegate> {
NSTextField *dateLabel;
NSTextField *weightLabel;
}
#property (strong) IBOutlet NSTextField *dateLabel;
#property (strong) IBOutlet NSTextField *weightLabel;
#end
#import "WeightPopoverController.h"
#implementation WeightPopoverController
#synthesize weightLabel;
#synthesize dateLabel;
#end
This is the code in my NSView subclass that opens up the popover:
#interface WeightGraphViewController () {
WeightPopoverController *popover;
WeightPopoverViewController *vc;
}
...
-(void)mouseEntered:(NSEvent *)theEvent {
// initialize the popover and its view controller
vc = [[WeightPopoverViewController alloc] init];
popover = [[WeightPopoverController alloc] init];
// configure popover
[popover setContentViewController:vc];
[popover setDelegate:popover];
[popover setAnimates:NO];
// set labels
for (id key in (id)[theEvent userData]) {
[popover.weightLabel setStringValue:[(NSDictionary*)[theEvent userData] objectForKey:key]];
[popover.dateLabel setStringValue:key];
}
// set the location
(redacted, irrelevant)
// show popover
[popover showRelativeToRect:rect ofView:[self window].contentView preferredEdge:NSMaxYEdge];
}
-(void)mouseExited:(NSEvent *)theEvent {
[popover close];
popover = nil;
}
In WeightPopoverViewController.xib, I've set the File's Owner to WeightPopoverViewController and connected the view to the custom NSView. In this xib I also have an Object set to WeightPopoverController with the dateLabel and weightLabel connected to their text fields and the contentViewController set to File's Owner.
I think where I am going wrong is likely related to how I have configured my class / instance variables for the NSPopover, but from the research I've done and documentation I've read I can't seem to crack where I've gone wrong. Any help would be appreciated.
UPDATE:
I removed the NSPopover subclass from code and from IB. I put my outlets in my NSViewController and connected them in IB. However, I'm still not able to set the string values. The following won't compile with the error "Property 'weightLabel' not found on object of type NSPopover*'".
#interface WeightGraphViewController () {
NSPopover *popover;
...
}
-(void)mouseEntered:(NSEvent *)theEvent {
vc = [[WeightPopoverViewController alloc] init];
popover = [[NSPopover alloc] init];
[popover setContentViewController:vc];
[popover.dateLabel setStringValue:#"test"];
}
I have the property definition exactly as I had it in my NSPopover subclass, but now in my NSViewController. This is actually what I had before, and since I wasn't able to set the properties from the NSViewController, I figured I needed to do it through a subclass of NSPopover. This is why I thought I am having an issue with how I have configured my class / instance variables.
You seem to be creating two popovers, one in code (popover = [[WeightPopoverController alloc] init]) and one in Interface Builder (In this xib I also have an Object set to WeightPopoverController). Have a think about what you’re trying to achieve.
I would also advise against subclassing NSPopover. I believe this is causing confusion and is unnecessary. Instead, put the outlets to your dateLabel and weightLabel in the popover’s content view controller.
I've experienced something that I think is similar. The root problem is that the "outlets" connecting your view (XIB) to your controller are not initialized until after the view has been displayed. If the controller tries to set properties on any UI controls in the view before the popover has been opened, those changes are ignored (since all the controls will be nil).
Luckily, there's an easy solution (as mentioned in this answer): just invoke the view getter on your controller, and it will force the view to initialize sooner.
In other words:
popover = [NSPopover new];
myController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
popover.contentViewController = myController;
[myController view]; // force view to initialize
...set some values on myController... // works because view is now loaded
[popover showRelativeToRect: ...];
CONFIGURATION:
-UIviewController embedded in Navigationcontroller.
-UIviewController has a UIscrollview as subview
-UIscrollview has some views where charts are created: each view containing a chart has its own .h and .m file and from this file I want trigger a segue to a tableview controller.
-A Tableviewcontroller was added in xcode and a segue from the UIviewController to the TableViewcontroller was created as well (Xcode)
-created a protocol in the UIView to have the segue pushed from there.
PROBLEM:
delegate always nil, segue method will never be called
UIVIEW .h file
#protocol UItoUIvcDelegate <NSObject>
-(void)triggerSegue;
#end
#interface CFfirstGraph : UIView <CPTPlotDataSource , CPTPieChartDelegate,UIActionSheetDelegate>
#property(weak, nonatomic) id <UItoUIvcDelegate> delegate;
#end
UIVIEW .m file (snippet)
-(void)pieChart:(CPTPieChart *)pieChart sliceWasSelectedAtRecordIndex:(NSUInteger)index
{
if (self.delegate == nil)
{
NSLog(#"nil");
}
[self.delegate triggerSegue];
}
UIVIEWCONTROLLER .h file
#import "CFfirstGraph.h"
#interface CFMainViewController : UIViewController <UItoUIvcDelegate, UITableViewDelegate, UITableViewDataSource>
#end
UIVIEWCONTROLLER .m file (snippet)
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.contentSize = CGSizeMake(320, 1000);
[self.view addSubview:self.scrollView];
CFfirstGraph *click =[[CFfirstGraph alloc]init];
click.delegate = self ;
}
-(void)triggerSegue
{
[self performSegueWithIdentifier:#"detailedData" sender:self];
NSLog(#"estoy aqui");
}
What am I doing wrong ? why the delegate is always nil ? I tried to add the method setDelegate but still no luck.
Thanks,
dom
Make CFfirstGraph as a strong property.
#property (strong, nonatomic) CFfirstGraph * click;
- (void)viewDidLoad
{
[super viewDidLoad];
self.click =[[CFfirstGraph alloc]init];
self.click.delegate = self ;
self.scrollView.contentSize = CGSizeMake(320, 1000);
[self.view addSubview:self.scrollView];
}
ok, after many hours of sweat I found the issue.
First...delegate = nil was not the main problem.
The real issue was the protocol method triggering the segue was never called.
If i create and initialize a CFfirstGraph object (or even property) it won't be related to the view created already in x-code, and this is the main issue.
On the other hand...if I "CTRL-drag" an outlet from the UIview to the CFMainViewController i will have a property that is exactly the one i need:
#interface CFMainViewController () <UIScrollViewDelegate>
#property (weak, nonatomic) IBOutlet CFfirstGraph *FirstGraph;
Then i assign the delegate to self (CFMainViewController) in the viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.FirstGraph.delegate = self ;
}
and the delegate method "triggerSegue" will be executed being called from the UIVIEW.
Best Regards,
dom
I have MainMenu.Xib which has a status menu element. The MainMenu File Owner is mapped to AppDelegate.
I also have another Xib which is a Window and it's File Owner is mapped to a ViewController with the same name.
So what I have tried and it kind of works is I have created an action in the appDelegate and have mapped the menu item in the status menu to the action in the appDelete using the First Responder.
In the action I have put:
SubscriptionsViewController *vc = [[SubscriptionsViewController alloc] initWithNibName:#"Subscriptions" bundle:nil];
[vc view];
If I step through the code it the window shows up but then goes away. So I have two questions
1) I thought there was a way to load the xib with NSMenuItem without the need of the above code.
2) How do I keep the window from closing right away? Do I need to save the view pointer or something?
edit: format code.
1) I thought there was a way to load the xib with NSMenuItem without the need of the above code.
Since NSWindow is not inherited from NSView like in iOS (UIWindow:UIView), it makes no sense to use NSViewController to load window from a xib. Use subclass of NSObject instead.
#interface SubscriptionsViewController : NSObject
#property (assign, nonatomic) IBOutlet NSWindow *window;
#end
#implementation SubscriptionsViewController
- (id)init
{
self = [super init];
if (self) {
[NSBundle loadNibNamed:#"Subscriptions" owner:self];
}
return self;
}
#end
2) How do I keep the window from closing right away? Do I need to save the view pointer or something?
It depends on the context to retain the instance of subscriptionsViewController or not. You can use below code to display a window, where the instance of window is in nib -
self.subscriptionsViewController = [[SubscriptionsViewController alloc] init];
[self.subscriptionsViewController.window makeKeyAndOrderFront:self];
Remember if "Visible At Launch" is set in nib, then the window is visible when you instantiate subscriptionsViewController.
You may add your window into the MainMenu.xib instead of using an addition xib file and create an outlet in the AppDelegare.h as
#property (assign) IBOutlet NSWindow *window;
Then all you need to do is
window.isVisible = !window.isVisible;
in the necessary action method...
I have a TableViewCOntroller that shows a list of images and associated descriptions. I pass data to the detailed view in the prepare for segue method. THe MSMutableDrictionary Object I pass has the correct values and I can see this in the NSLog of the object in the detail views viewDidLoadMethod. THe code for this is as follows:
.h of detail view controller
#interface sitespecLargeImageDetail : UIViewController
#property (strong, nonatomic) NSMutableDictionary *details;
#property (strong, nonatomic) IBOutlet UIImage *largeImage;
#property (strong, nonatomic) IBOutlet UILabel *largeImageLabel;
#end
.m of detail view controller
#implementation sitespecLargeImageDetail
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_largeImage = [_details valueForKey:#"pbvurl"];
_largeImageLabel = [_details valueForKey:#"pbvdesc"];
NSLog(#"%#", _largeImageLabel);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here is the prepare for segue event in the tableviewcontoller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
sitespecLargeImageDetail *detailViewController = (sitespecLargeImageDetail *)segue.destinationViewController;
detailViewController.details = _dictObj;
}
Couple of strange things:
WHen I look at the detail view controller in my storyboard in the connections inspector, I can see both the label and image Outlets. I can see I ahve connected the label outlet. great, but it does not update when the view loads! I know the dict obj in the detail view gets data because I can NSLog it and see it. I use that to set the IBOutlet for the label but nothing.
In the connection inspector, I can see the UIImage outlet BUT I am unable to connect it to the UIImage VIew I placed in the detail view controller, it simply wont allow me to connect it, no error, just when I control drag from the detailview controller I dont even see it! I see the label outlet, but not the image view.......
Firstly, what you want to do is _largeImageLabel.text = [_details valueForKey:#"pbvdesc"];.
Without the .text what you are doing is using the UILabel pointer to point to a NSString, which clearly does not result in your expected behaviour!
As for the UIImage outlet, what you need is a UIImageView outlet! UIImage is not a view, hence it doesn't have any relation with the interface builder (you can't drag a UIImage in your storyboard, only views can compose interfaces).
I'm trying to create a simple Quiz app (I'm a beginner), when I launch the app I want a UILabel to show the first question (of an array of questions). I'm having some trouble with setting the initial value.
I've done a couple of attempts, whiteout success. I my QuizAppDelegate.h file I declare my UILabel like this:
IBOutlet UILabel * questionField;
In my main .m file I have tried the following:
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
questionField = [[UILabel alloc] init];
[questionField setText:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
Another thing I have tried is the following in QuizAppDelegate:
#property (nonatomic, retain) IBOutlet UILabel *questionField;
- (void)changeTitle:(NSString *)toName;
And in the .m file:
#synthesize questionField;
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
[self changeTitle:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
-(void)changeTitle:(NSString *)toName {
[questionField setText:toName];
}
Any tips on how to solve this would be great!
// Anders
Hopefully you're not actually putting code into main.m. On iOS, you rarely modify that file.
Since you're doing everything in the AppDelegate, let's keep it there (as opposed to creating a new UIViewController). Let's start with the basics.
Adding the Label as an instance variable
You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;
Then, declare the corresponding property, and make sure to synthesize it in the .m file.
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#synthesize questionField // in the .m file
Adding the UILabel in Interface Builder
Open up MainWindow.xib. Drag a UILabel from the Library to the Window that represents your app's window. Then Control-Drag from the AppDelegate object (the third icon on the left in Xcode 4; it'll be labelled in the Document window in IB 3). You'll see a little black window come up—select the option called questionField to make the connection.
See this link for screenshots and how to make connections in IB. The same applies in Xcode 4.
Changing the text
You don't need a separate method to change the text—just modify the label's text property.
Pick a method that'll be called when the app launches (applicationDidFinishLaunching:WithOptions: is a good place to do it in), and put the following code:
questionField.text = #"Hello";
And that's it!
Code
QuizAppDelegate.h
#import <UIKit/UIKit.h>
#interface QuizAppDelegate : NSObject <UIApplicationDelegate> {
IBOutlet UILabel *questionField;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#end
QuizAppDelegate.m
#import "QuizAppDelegate.h"
#implementation QuizAppDelegate
#synthesize window=_window;
#synthesize questionField;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the tab bar controller's current view as a subview of the window
[self.window addSubview:self.questionField];
[self.window makeKeyAndVisible];
self.questionField.text = #"Hello";
return YES;
}
- (void)dealloc
{
[_window release];
[questionField release];
[super dealloc];
}
#end
If you're creating the label programmatically, then you have to add the label to the view:
[self.view addSubview:questionField];
This assumes that you have a ViewController. If not, and you're doing this directly in the AppDelegate (a very bad idea, by the way), then do
[self.window addSubview:questionField];
If you're creating it in the IB, make sure you set up the connections.
You should not both add the UILabel in the IB and instantiate it programmatically. Only call alloc if you are creating it programmatically. Otherwise, if using the IB, skip that part. You created it already with the xib.
I suspect that you have either not created your Interface Builder layout properly - either you have missed the control out all together or more likely you have not connected that control to the questionField outlet in yout header file.
You need to drag a UILabel view into the main view and then connect it to the correct line in your header file.
You shouldn't be using your main.m like that at all. In fact, you should almost certainly never do anything with it. Try creating a UIViewController subclass and practicing your quiz with that. (Add the UILabel to the IB file and then connect the outlet.) Perhaps use the View-Based Application template while you are practicing.
This is a good answer:
"You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;"
I was trying to change the value of mylabel.text and the screen didn't update the label with this.value. I included the {IBOutlet UILabel * mylabel} and it works like a charm!
So this answer is valid to change the text of a label programmatically!
Thanks