setNeedsDisplay not updating interface - objective-c

When calling [polygonShapeView setNeedsDisplay]; my polygonShapeView drawRect method is NOT called. I am able to do polygonShapeView.hidden = YES, which works fine so I have a good reference to the view and have hooked up my outlet. Any ideas?
Controller.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "PolygonShape.h"
#import "PolygonShapeView.h"
#interface Controller : NSObject {
IBOutlet UIButton *decreaseButton;
IBOutlet UIButton *increaseButton;
IBOutlet UILabel *numberOfSidesLabel;
IBOutlet PolygonShape *polygonShape;
IBOutlet PolygonShapeView *polygonShapeView;
IBOutlet UILabel *polygonLabel;
}
- (IBAction)decrease:(id)sender;
- (IBAction)increase:(id)sender;
- (void)awakeFromNib;
- (void)updateInterface;
#end
Controller.m
//
// Controller.m
//
// Created by Chris Muench on 6/24/11.
// Copyright 2011 N/A. All rights reserved.
//
#import "Controller.h"
#implementation Controller
- (IBAction)decrease:(id)sender
{
[polygonShape setNumberOfSides:numberOfSidesLabel.text.integerValue - 1];
[self updateInterface];
}
- (IBAction)increase:(id)sender
{
[polygonShape setNumberOfSides:numberOfSidesLabel.text.integerValue + 1];
[self updateInterface];
}
- (void)awakeFromNib
{
polygonShape = [[PolygonShape alloc] initWithNumberOfSides:numberOfSidesLabel.text.integerValue minimumNumberOfSides:3 maximumNumberOfSides:12];
[self updateInterface];
}
- (void)updateInterface
{
[polygonShapeView setNeedsDisplay];
numberOfSidesLabel.text = [NSString stringWithFormat:#"%d",polygonShape.numberOfSides];
polygonLabel.text = polygonShape.name;
if (polygonShape.numberOfSides == polygonShape.maximumNumberOfSides)
{
increaseButton.enabled = NO;
}
else
{
increaseButton.enabled = YES;
}
if(polygonShape.numberOfSides == polygonShape.minimumNumberOfSides)
{
decreaseButton.enabled = NO;
}
else
{
decreaseButton.enabled = YES;
}
}
#end

I can only guess, but it seems your polygonShapeView is not linked in any way to the polygonShape. So it might draw, but not according to the data you expect.
I think there should be something like polygonShapeView.shape = polygonShape; in awakeFromNib, or in updateInterface.

Related

NSToolbar created programmatically starts empty and won't save

I'm currently trying to write a Mac application. In doing so, I'm having some peculiar problems when trying to setup an NSToolbar.
Although I have setup all the components as per the API documentation, when the application loads, the toolbar always starts empty. When I open the customisation pane, the toolbar items are there, and I can drag them into the toolbar, but when I quit the application and restart the changes are gone.
Note: I am aware that many of you will be of the opinion that the best way to solve this is to use interface builder rather than doing it in code. That is not the answer I am looking for - I chose to make this application without IB in order to better understand the internals of a Cocoa app.
I have verified (with NSLogs) that neither the toolbarAllowedItemIdentifiers nor the toolbarDefaultItemIdentifiers delegate methods get called when the toolbar is first initialised, but they do get called when you enter the customisation pane.
Below, please find a minimal, verifiable and complete example version of a basic app that demonstrates this bug. Anyone that can shed some light on this matter would be hugely appreciated!
Thanks
Defines.h
#define UNUSED(x) (void)(x)
#define TOOLBAR_ONE #"ONE"
#define TOOLBAR_TWO #"TWO"
#define TOOLBAR_IDENT #"TOOLBAR"
#define WINDOW_MASK NSTitledWindowMask | \
NSClosableWindowMask | \
NSResizableWindowMask | \
NSMiniaturizableWindowMask
main.m
#import "BWAppDelegate.h"
#import <AppKit/AppKit.h>
int main(void) {
#autoreleasepool {
NSApplication* application = [NSApplication sharedApplication];
BWAppDelegate* delegate = [[BWAppDelegate alloc] init];
application.delegate = delegate;
[application run];
return EXIT_SUCCESS;
}
}
BWAppDelegate.h
#import <Cocoa/Cocoa.h>
#import "BWMainToolbarDelegate.h"
#interface BWAppDelegate : NSObject<NSApplicationDelegate>
#property (atomic, strong) NSWindow* window;
#property (atomic, strong) BWMainToolbarDelegate* toolbarDelegate;
#end
BWAppDelegate.m
#import <AVFoundation/AVFoundation.h>
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
#import "BWAppDelegate.h"
#import "Defines.h"
#implementation BWAppDelegate
#synthesize window, toolbarDelegate;
- (void) applicationDidFinishLaunching: (NSNotification*) aNotification
{
UNUSED(aNotification);
NSRect dims = NSMakeRect(0, 0, 300, 300);
self.window = [[NSWindow alloc] initWithContentRect:dims
styleMask:WINDOW_MASK
backing:NSBackingStoreBuffered
defer:NO];
[self.window makeKeyAndOrderFront:nil];
self.window.toolbar = [[NSToolbar alloc] initWithIdentifier:TOOLBAR_IDENT];
toolbarDelegate = [[BWMainToolbarDelegate alloc] initWithToolbar:self.window.toolbar];
}
#end
BWMainToolbarDelegate.h
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#interface BWMainToolbarDelegate : NSObject<NSToolbarDelegate>
- (instancetype) initWithToolbar: (NSToolbar*) theToolbar;
- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*) toolbar;
- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*) toolbar;
- (NSToolbarItem*) toolbar: (NSToolbar*) toolbar
itemForItemIdentifier: (NSString*) identifier
willBeInsertedIntoToolbar: (BOOL) flag;
#end
BWMainToolbarDelegate.m
#import "BWMainToolbarDelegate.h"
#import "Defines.h"
#implementation BWMainToolbarDelegate {
NSToolbar* toolbar;
}
- (instancetype) initWithToolbar: (NSToolbar*) theToolbar
{
self = [super init];
if(self) {
toolbar = theToolbar;
toolbar.displayMode = NSToolbarDisplayModeIconAndLabel;
toolbar.allowsUserCustomization = YES;
toolbar.autosavesConfiguration = YES;
toolbar.delegate = self;
}
return self;
}
- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*) theToolbar
{
UNUSED(theToolbar);
return #[TOOLBAR_ONE, TOOLBAR_TWO];
}
- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*) theToolbar
{
UNUSED(theToolbar);
return #[TOOLBAR_ONE, TOOLBAR_TWO];
}
- (NSToolbarItem*) toolbar: (NSToolbar*) theToolbar
itemForItemIdentifier: (NSString*) identifier
willBeInsertedIntoToolbar: (BOOL) flag
{
UNUSED(flag);
NSToolbarItem* returnVal = nil;
NSString* label;
if([theToolbar.identifier isEqualToString:TOOLBAR_IDENT]) {
if([identifier isEqualToString:TOOLBAR_ONE]) {
returnVal = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_ONE];
label = #"Toolbar One";
} else if([identifier isEqualToString:TOOLBAR_TWO]) {
returnVal = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_TWO];
label = #"Toolbar TWO";
}
}
returnVal.label = label;
returnVal.paletteLabel = label;
return returnVal;
}
#end
Set the delegate of the toolbar before adding the toolbar to the window.

how do I push a view controller from a ViewCell in a UICollectionView

I'm trying to use a UICollectionView and it's viewCell. I have that going fine. But on the viewcell form I have a button that I intend to have go to a settings view. I'm trying to "push it onto the stack". Xcode complains of "no visible interface for the selector". Some code and the error message are below.
// TryColViewCell.h
#import <UIKit/UIKit.h>
#import "TryColViewContViewController.h"
#interface TryColViewCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UILabel *outletNameLBL;
#property (weak, nonatomic) IBOutlet UILabel *outletCellLabel;
#property (readwrite) NSInteger intTest;
#property (readwrite) TryColViewContViewController *theHost;
- (IBAction)actionPlus1:(id)sender;
- (IBAction)actionMinus1:(id)sender;
- (IBAction)actionNameEdit:(id)sender;
// TryColViewCell.m
#import "TryColViewCell.h"
#import "SettingsViewController.h"
#implementation TryColViewCell {
#public int intCellNumber; //TODO: get this to track the row/cell #
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (IBAction)actionPlus1:(id)sender {
}
- (IBAction)actionMinus1:(id)sender {
}
- (IBAction)actionNameEdit:(id)sender {
NSLog(#"Name Edit");
SettingsViewController *viewControllerB =
[[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:nil];
viewControllerB.propName = _outletNameLBL.text;
[self pushViewController:viewControllerB animated:YES];
[self.theHost pushViewController:viewControllerB animated:YES];
}
#end
// Error message on PushVIewController line
TryColViewCell.m:83:11: No visible #interface for 'TryColViewCell'
declares the selector 'pushViewController:animated:'
Push the new view controller from the view controller that contains the collection view, not the cell. Only a subclass of UIViewController has the method pushViewController:animated. to override.
In your table view controller, do something like this, assuming you are using storyboard:
-(UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
static NSString* identifier = #"Cell";
CellSubClass *cell =
(CellSubClass*) [tableView dequeueReusableCellWithIdentifier:identifier];
[cell.upButton addTarget:self selector:#selector(actionPlus1:)
forControlEvent:UIControlEventTouchUpInside];
[cell.downButton addTarget:self selector:#selector(actionMinus1:)
forControlEvent:UIControlEventTouchUpInside];
...
}

iphone-"Use of Undeclared Identifier 'textFieldShouldReturn' Objective C

I've hit an "Use of Undeclared Identifier" Error. Seems there could be a lot of reasons for this, and I couldn't see what the problem was with mine. First, here's the code:
#import "CMViewController.h"
#import "CMAEncode.h"
#interface CMViewController ()
#property (weak, nonatomic) IBOutlet UITextView *toCode;
#property (weak, nonatomic) IBOutlet UITextView *Coded;
#property (weak, nonatomic) IBOutlet UISwitch *onOrOff;
- (IBAction)StartEncodeDecode:(id)sender;
#end
#implementation CMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)StartEncodeDecode:(id)sender {
NSString *finishedText;
NSString *toCode = self.toCode.text;
if (self.onOrOff.on == TRUE) {
finishedText = [CMAEncode encodeText:toCode];
self.Coded.text = finishedText;
} else {
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField // Undeclared Identifier here.
{
[textField resignFirstResponder];
return YES;
}
}
#end
I'm trying to make a textfield resign first responder so the keyboard will return. But I really just want to know why this error is occurring, it might help people out with future instances of this error.
You have defined a method inside another method which is not allowed in any language objective-c. Please move textFieldShouldReturn: after StartEncodeDecode: method as below
- (IBAction)StartEncodeDecode:(id)sender {
NSString *finishedText;
NSString *toCode = self.toCode.text;
if (self.onOrOff.on == TRUE) {
finishedText = [CMAEncode encodeText:toCode];
self.Coded.text = finishedText;
} else {
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}

SubClassing UILabel

I read in this same site how to inset and UILabel (subclass UILabel and override the required methods). Before adding it to my app I decided to test it out in a standalone test app. Code is shown below.
Here's MyUILabel.h
#import <UIKit/UIKit.h>
#interface MyUILabel : UILabel
#end
Here's MyUILabel.m
#import "MyUILabel.h"
#import <QuartzCore/QuartzCore.h>
#implementation MyUILabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// for border and rounding
-(void) drawRect:(CGRect)rect
{
self.layer.cornerRadius = 4.0;
self.layer.borderWidth = 2;
[super drawRect:rect];
}
// for inset
-(void) drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect: UIEdgeInsetsInsetRect(rect, insets)];
}
Here's my ViewController.h
#import <UIKit/UIKit.h>
#import "MyUILabel.h"
#interface ViewController : UIViewController
{
MyUILabel *myDisplay;
}
#property (strong, nonatomic) IBOutlet MyUILabel *myDisplay;
#end
Here's ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myDisplay;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
myDisplay.text = #"Hello World!";
}
- (void)viewDidUnload
{
[self setMyDisplay:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
None of the methods in MyUILabel.m (that Im overriding) get called.
Insights into why are greatly appreciated.
Regards,
Ramon.
Ok. I did some further digging and in Xcode there is a field visible when looking at the nib file. Its the 'Identity Inspector' (3rd icon from left). This needed to be changed from UILabel to MyUILabel.
Now it works!

ios retrieve when uitabbarcontroller item is selected

I need to retrieve when a user click over a tabbaritem into a uitabbarcontroller to change something..
here is my code:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
if (item == [tabBarController.tabBar.items objectAtIndex:2]) {
item.title = #"add shot";
}
else
{
item.title = #"Race";
}
}
but If I do this:
self.tabBarController.tabBar.delegate = self;
i receive a sigkill...
what's the right solution? thanks in advance
Does your view controller conform to the UITabBarDelegate protocol?
In the header file:
#interface MyViewController : UIViewController<UITabBarDelegate> {
// ...
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
#end
Then, just do:
tabBar.delegate = self;
Instead of:
self.tabBarController.tabBar.delegate = self;
And:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
//self.tabBarItem.title = #"Title";
}
I came across this answer while learning iOS development, But I wanted to include the little missing pieces for n00bs like me.
// HelloWorldViewController.h
#interface HelloWorldViewController : UIViewController <UITabBarDelegate>
{
}
#property (weak, nonatomic) IBOutlet UITabBar *tabBar;
#end
And
// HelloWorldViewController.m
#interface HelloWorldViewController ()
#end
#implementation HelloWorldViewController
#synthesize tabBar;
- (void) viewDidLoad
{
tabBar.delegate = self;
}
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
NSLog(#"didSelectItem: %d", item.tag);
}
#end