Cocoa / Objective-C: Access a (Boolean) variable in different Classes - objective-c

Situation:
Noob / Xcode 3.1
I have an AppView (NSView subclass) and an AppController (NSObject subclass)
in AppView.h i declare a boolean (BOOL: booleanDraw), which i set to 'NO' in AppView.m
When a button is clicked it 'launches' an action (AppController .h/.m) now i want to change booleanDraw to YES when the button is clicked.
I searched and found: do it with #property okay i tried to do that but it didnt work. (because i didnt totally get what to do probably)
i did:
#property BOOL booleanDraw;
(in AppView.h)
#implementation AppView
#synthesize(readwrite, nonatomic) booleanDraw;
(in AppView.m)
AppView *obj;
obj.booleanDraw = YES; // implicitly calls [obj setVar:3]
(in AppController.m)
Thanks for any help, i read some tutorials already but often they suggest some steps that should be basic but that dont belong to my repertoire, and the ADN often confuse me xD sorry but believe me im trying^^

You just reversed the synthesize and property statements:
in .h:
#property (nonatomic) booleanDraw;
(by default properties are readwrite, you only need to state when they are readonly)
in .m:
#synthesize booleanDraw;
In the controller you need to get the app view reference, the code you posted would not work unless you set "obj" to something.

Related

Using a button to create a custom class instance and show it in an NSTableView

Im stuck on this problem and it's driving me crazy. What I am attempting to do is have a button click create an instance of a custom class, set it's variables, add it to an NSMutableArray, and display it in a table view. So far it seems that I have everything working except having the info display in the table view.
My custom class TradePaperback just has three NSString properties: title, volume, and publisher.
Here is the code for my header and implementation files:
Header:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (nonatomic, strong) NSMutableArray *tradeArray;
#property (weak) IBOutlet NSTableView *tableView;
- (IBAction)addTrade:(id)sender;
#end
implementation file:
#import "AppDelegate.h"
#import "tradePaperback.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
-(NSMutableArray *)tradeArray{
if (!_tradeArray){
_tradeArray = [[NSMutableArray alloc]init];
TradePaperback *avengers = [[TradePaperback alloc]init];
avengers.title = #"Avengers";
avengers.volume= #"volume 01";
avengers.publisher = #"Marvel Comics";
[_tradeArray addObject:avengers];}
return _tradeArray;}
- (IBAction)addTrade:(id)sender {
TradePaperback *newTrade = [[TradePaperback alloc]init];
newTrade.title = #"New Trade";
newTrade.volume = #"Volume Number";
newTrade.publisher = #"publisher";
[_tradeArray addObject:newTrade];
NSLog(#"added");
NSLog(#"number of items in array is %ld", _tradeArray.count);
[_tableView reloadData];}
#end
My table view is hooked up using bindings. It seems that everything is hooked up correctly since the avengers instance of TadePaperback that i put in shows up when I run the program. As I click the add button I can see from the log in the console that the array is having items added to it, but they just won't display.
Why would the tableView show the first item in the array, but none of the rest?
Here is a picture of the program after running and clicking the add button a couple of times.
program running
I would greatly appreciate any help or advice you guys could give. Thanks in advance.
-Jack
If you're using bindings to populate a table view, you're almost certainly using an NSArrayController to manage the table's content. If you want to add an object to the array controlled by this controller (your tradeArray object), you should do so indirectly: add to the array controller, which will in turn update your array. NSArrayController provides a number of add... or insert.. methods; decide which one suits you best, and use it to replace your call to [_tradeArray addObject:...].
The reason this approach works, and yours doesn't is because this engages the key-value coding/observing machinery that underpins bindings. Your approach essentially adds the object behind the array controller's back - it's not KVO/KVC-compliant, so the array controller remains unaware of the change. Cocoa does provide you with a way of editing the original array in a KVO/KVC-friendly manner if you so wish, it's just a little more work: try the code below, then read Apple's NSKeyValueCoding Protocol Reference and their Key-Value Coding Programming Guide for an explanation:
// Instead of [_tradeArray addObject:newTrade];
[[self mutableArrayValueForKey:#"_tradeArray"] addObject:newTrade];

No Setter method for assignment to property - cocoa application

I'm fairly new to objective-c and have just encountered an error i've not seen before.
I'm trying to set a Text Field cell as 'selectable', but i get the error "No Setter method 'setIsSelectable' for assignment to property."
Here are the .h and .m files.
Thanks.
DataPanel.h
#import <Cocoa/Cocoa.h>
#interface DataPanel : NSPanel
#property (weak) IBOutlet NSTextFieldCell *textField;
#end
DataPanel.m
#import "DataPanel.h"
#implementation DataPanel
#synthesize textField = _textField;
- (void) awakeFromNib{
_textField.stringValue = #"1.1 Performance standards The overall objective of the performance standards in Section 1.1 is to provide acoustic conditions in schools that (a) facilitate clear communication of speech between teacher and student, and between students, and (b) do not interfere with study activities.";
_textField.isSelectable = YES;
}
#end
In Objective-C, BOOL properties which start with 'is' are usually the getter of the property only, and not the property itself.
Its a convention.
Just for general knowledge, you can do so yourself by declaring properties in the following manner:
#property (nonatomic, getter=isAvaiable) BOOL available;
So trying to set the above, while using isAvailable will not work, since it is the getter method, and you can't set a getter.
As for your question,
Try changing your code from _textField.isSelectable = YES; to either of the below, and it should work.
_textField.selectable = YES;
[_textField setSelectable:YES];
Good luck mate.

How do I know if not declaring #synthesize will result in "use of undeclared identifier"?

In one of the assignments, I had to override the superclass's getter method for the game logic (so the method will get the subclass of the game logic instead of the original one).
CardGameViewController.h:
#import <UIKit/UIKit.h>
#import "Deck.h"
#import "CardGame.h"
#interface CardGameViewController : UIViewController
#property (nonatomic) NSUInteger startingCardCount; // abstract
#property (strong, nonatomic) CardGame *game;
- (Deck *)createDeck; // abstract
- (void)updateCell:(UICollectionViewCell *)cell usingCard:(Card *)Card; // abstract
#end
CardGameViewController.m:
#import "CardGameViewController.h"
...
// no #synthesize here, but works fine.
- (CardGame *)game
{
if (!_game) _game = [[CardGame alloc] initWithCardCount:self.startingCardCount
usingDeck:[self createDeck]];
return _game;
}
...
#end
SetCardGameViewController.m:
...
#interface TSSetCardGameViewController()
#property (strong, nonatomic) CardGame *game;
#end
#implementation TSSetCardGameViewController
#synthesize game = _game; // Compiler *will* complain if this line is commented out.
- (CardGame *)game
{
if (!_game) _game = [[SetCardGame alloc] initWithCardCount:self.startingCardCount
usingDeck:[self createDeck]];
return _game;
}
...
#end
Then I got "Use of undeclared identifier" for "_game". so I declared
#property (strong, nonatomic) CardGame *game;
But I got the same error, so I used "self.game" instead, which caused a bad access exception.
I couldn't find anything on Google, so I tinkered around until I found that this solves the problem:
#synthesize game = _game;
Now, my question is why. My understanding is the new version of Xcode does the synthesizing for me, unless I override both its getter and setter. I did override the getter, but not the setter, so Xcode technically should have included it automatically. The proof is that Xcode did not complain until I subclassed CardGameViewController and specifically overrode the getter method. (FYI neither CardGameViewController nor its subclass had a setter method for *game)
So I'm a little confused. Please help!
The problem here is that you have two versions of _game. Since the introduction of the new ABI (64-bit Mac and all iOS), each subclass can create its own ivars without tromping all over its superclass's ivars (even if they're named the same). And ivars created by #synthesize are private. Now hold that thought and let's see what's happening:
In your superclass, you declare a property that has a getter and setter (though you almost certainly don't mean to have a setter…) You override the getter. The compiler says "but you still want me to create a setter for you, so I'll create an ivar to match it."
In your subclass, you declare no new properties. You may think you do, but it's just the same property that comes from the superclass; it's not a new property. There's already a getter and setter in the superclass, so there's no need for the compiler to create an ivar.
You then reference an ivar that does not exist in your subclass. It only exists as a private ivar in the superclass. The compiler can't see that (and wouldn't let you access it even if it could).
The typical solution to this problem is, rather than overriding -game, just provide a class method called +gameClass and have it return the correct class to instantiate. (See +layerClass in UIView for an example of this pattern.)

issue using access privileges

I have two view controllers and nibs. I populated one view controller with a toggle switch and declared this in its header file:
#public UISwitch *toggleSwitch;
and exposed it as a property like this:
#property (nonatomic,retain) IBOutlet UISwitch *toggleSwitch;
I also connected the switch with toggleSwitch outlet. Now I want to use this toggleSwitch field in my other view controller, how do I do that? Isn't using #public in the field declaration enough? Please help. Thank you.
No problem at all. Just use the switch like this:
vcWhereYouDeclaredTheSwitch.toggleSwitch.on = YES;
or
BOOL test = [vcWhereYouDeclaredTheSwitch.toggleSwitch isOn];
inside your other view controller.
Here are some general thoughts about propertys:
Memory management : Behind the scenes it will create a setter which creates the variable with correct memory management. It will save you some headaches because you can easily see how the memory management is done (strong/weak and retain/copy/assign).
Accessibility from other classes: if you declare your #property in the .h and #synthesize it in the .m you ivar will be public readable and writeable. You can prevent this with a privat class extension. You even can declare a #property public readonly and declare them internally readwrite via a privat class extension.
Eg: a private property
// [In the implementation file]
#interface MyClass ()
#property (nonatomic, retain) NSMutableArray* someData; // private!!
#end
#implementation MyClass #synthesize someData
#end
Custom getter and setter: If you like you can still write custom getter and setters and you can even just write a getter or setter and let the other one automatically #synthesize. And you can write custom logic into such a getter and setter e.g. you can reload a tableview after a #property has changed.
Automatic Key-Value-Observing (KVO) compliant: If you use or planning to use KVO you get it basically for free by just declaring the property. Nothing else need to be done!
If you need you iVar to be public it is simpler to write one #property than writing a getter and setter for a iVar
With a #property you do not need to declare in iVar (in iOS and 64bit Mac Os X applications). You can do it via the #synthesize:
#synthesize myiVar = _myIvar;
You have made the property of UISwitch. So, you can use it anywhere by using the viewcontroller object.
Suppose you wanna use it in the view where you are currently then use it
self.toggleSwitch
// or
viewControllerObject.toggleSwitch

is it right way in obj-c programming

i wonder if the way i programm is right way or not. can you help me?
#interface ViewController : UIViewController
{
UILabel *messageLabel;
}
#end
when i declare new object in .h and create in .m i have to use #property (nonatomic, retain) UILabel *messageLabel? i saw few listings where when object are created by code #property doesn't exist and few where does exist and i'm confused.
is it correct when i don't use #property (in example for UILabel, UIImageView, UIButton) when i create objects by code?
#property is a key word useful to create setter/getter methods automatically for that field. If you don't need to access your label from outside your view controller you won't need to use #property and your code is fine.
Your code is correct. #property is used globally throughout your app, rather than being specific to your UIViewController. If you are only planning on referring or changing the label/other component define it within the { } otherwise #property should be used