Property of two classes [duplicate] - objective-c

This question already has an answer here:
How to make a property of a property
(1 answer)
Closed 9 years ago.
I want to have a result that looks like this player.type.property, An example of this is with UILabel, self.label.text. The .text being the property of the two classes.
A suggestion I have had is to do something like this:
player.type = [[MyCustomObject alloc] init];
player.type.property = #"value";
Although I'm not quite sure exactly how to go about doing this correctly, every method I have tried doesn't work.
Here is what I have tried:
Marketplace.h
#import "Item.h"
#interface Marketplace : NSObject
#property (nonatomic, assign) Item *market;
Item.h
#interface Item : NSObject
#property (nonatomic, assign) int price;
Starter.m
#import "Marketplace.h"
#import "Item.h"
#implementation MainGameDisplay
{
Marketplace *market;
Item *itemName;
}
-(void) executedMethod {
market.itemName = [[market alloc] init];
//2 errors: "Property 'itemName not found on object of type 'MarketPlace'" and "No visible #interface for 'MarketPlace' declares the selector alloc"
market.itemName.price = 5; //"Property 'itemName' not found on object of type 'Marketplace*'"
}

Each pointer to class object must be alloc init, so you need to over-write the -(id)init inside its class.
Item.h
#interface Item : NSObject
#property (nonatomic) NSInteger price;
Marketplace.h
#import "Item.h"
#interface Marketplace : NSObject
#property (nonatomic, strong) Item *item;//Item is a class, must use strong or retain
Marketplace.m
-(id)init{
if (self = [super init]) {
self.item = [[Item alloc] init];//Item must alloc together when MarcketPlace init
}
return self;
}
*Then you just init the Marketplace
#implementation MainGameDisplay
{
Marketplace *market;
Item *itemName;
}
-(void) executedMethod {
market = [Marketplace alloc] init];
//Now you can access
market.item.price = 5;
}

1 . make a Interface named PlayerType Put some property there and synthesize them.
2. now make a Interface named Player and import the PlayerType Interface there.
3. make a property of PlayerType Interface like #property(nonatomic, strong) PlayerType *type.
now made variable of Player it will allow you to access property of a property.

Related

objective-c: Using NSManagedObject for saving data with CoreData

Is it possible to extend an derived class from NSManagedObject? I'm asking this because I tried to do it. My entity looks like this:
So this means a class similar to the following code should be generated:
#import <Foundation/Foundation.h>
#interface Player : NSManagedObject
#property (nonatomic, copy) NSNumber* orderNumber;
#property (nonatomic, copy) NSString *name;
#end
.m file
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
#end
This two variables are saved to the SQLite database.
Now since I need some additional variables for the player I just added them to the class. It still worked.
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
- (id) init
{
self = [super init];
if (self != nil)
{
[self reset];
}
return self;
}
#synthesize isStillInGame = _isStillInGame;
- (void) reset
{
_isStillInGame = TRUE;
}
- (void) setOutOfGame
{
_isStillInGame = FALSE;
}
#end
But now when I change the isStillInGame bool, all instances of the Player Class are changed. Is this normal or do I have an error in my code?
A second question I can't answer is, why I can't access the object variables while debugging. When I try to watch an Player instance variable I just see this:
Is it possible to see more?

Readonly, non-mutable, public and readwrite, mutable, private #property: more information?

I want to expose an NSArray to my user (and I want them to only read it), but in my class, I want to use an NSMutableArray.
I tried the following code and it does not raise any warning:
// In the .h
#interface MyClass : NSObject <NSApplicationDelegate>
#property (nonatomic, readonly) NSArray * test ;
#end
and
// In the .m
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSMutableArray * test ;
#end
#implementation MyClass
- (id)init
{
self = [super init];
if (self)
{
self.test = [[NSMutableArray alloc] init] ;
}
return self;
}
#end
But, if I try to access the #property test from within my class, I can use the method addObject:. So, I guess what precedes is not possible.
Why is there no warning as it is?
I don't think that mixing property type would be a good practice. Instead I would create an accessor that returns a copy of the private mutable array. This is more conventional. Please note, don't use self for property access in your -init: method:
// In the .h
#interface MyClass : NSObject <NSApplicationDelegate>
- (NSArray *)test;
#end
// In the .m
#interface MyClass ()
#property (nonatomic, strong) NSMutableArray *aTest;
#end
#implementation MyClass
- (id)init
{
self = [super init];
if (self)
{
_aTest = [[NSMutableArray alloc] init] ;
}
return self;
}
- (NSArray *)test
{
return [self.aTest copy];
}
#end
The #property is just syntax sugar which automatically creates getter/setter methods for you. With the readonly in the .h file only the getter method will be created for the public but by overriding it in the .m file you get both methods in your implementation.
readwrite is the default (see here) so even if leave out readwrite put still have the #property in you implementation file you will get a setter method. It is good practice to explicitly write readwrite then in your .m file so you and other will get a hint that this variable might only be declared read only in the .h file.

Objective-C class returning (null) for control values?

I am trying to make a TableViewController.. I got it to work using code from a youtube lesson: "Cocoa Programming L13-14" But then when I try to change it so that the default values aren't hard coded... but rather the values of controls in the Interface Builder, I get (null) across the board. Here is the code:
#import <Foundation/Foundation.h>
#interface Person : NSObject {
IBOutlet NSPathControl* pcSource;
IBOutlet NSPathControl* pcDestination;
IBOutlet NSTextField* tfBackupAmount;
NSURL* urlSource;
NSURL* urlDestination;
NSString* strBackupAmount;
//Old--
//NSString* name;
//int age;
}
#property NSURL* urlSource;
#property NSURL* urlDestination;
#property NSString* strBackupAmount;
//Old--
//#property (copy) NSString* name;
//#property int age;
#end
and
#import "Person.h"
#implementation Person
#synthesize urlSource;
#synthesize urlDestination;
#synthesize strBackupAmount;
//Old--
//#synthesize name;
//#synthesize age;
- (id)init {
self = [super init];
if (self) {
urlSource = [pcSource URL];
urlDestination = [pcDestination URL];
strBackupAmount = [tfBackupAmount stringValue];
NSLog(#"%#\n%#\n%#",urlSource,urlDestination,strBackupAmount);
//Old--
//name = #"Yoda";
//age = 900;
//NSLog(#"%#: %i", name, age);
}
return self;
}
#end
Everything commented //Old-- worked, and interacted fine with the TableViewController. So I am assuming all that still works fine. The 3 controls (2 NSPathControl & 1 NSTextField) are linked up to an Object class:Person in Interface Builder with the controls linked up. Why am I getting output of:
(null)
(null)
(null)
? When I get to the NSLog(); line? Where am I going wrong?
Thanks!
pcSource, pcDestination, or tfBackupAmount aren't initialized when your init method is called, so they're all nil. Sending a message to nil is legal in Objective-C, and you'll just get nil back. That means urlSource, urlDestination, and strBackupAmount are all nil too, and that's why you ge the log output you're seeing.
You need to change the log message to sometime after those variables are initialized.
Try putting the code in -viewDidLoad rather than -init. It all has to do with the order of events (-init gets called before any of the IB stuff happens.
Ok, technically this question - I found an answer for it. It is to make a custom init method. In my case this means:
Person* p = [[Person alloc] initWithurlSource:[NSURL URLWithString:#"moo"] andurlDestination:[NSURL URLWithString:#"cow"] andstrBackupAmount:#"foo"];
However this still doesn't solve my problem of getting values for IBOutlets from another Class (in this case my TableViewController class) that has been exposed as #property:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
.....
.....
#property (nonatomic, retain) NSPathControl* pcSource;
#property (nonatomic, retain) NSPathControl* pcDestination;
#property (nonatomic, retain) NSTextField* tfBackupAmount;
I am still having trouble getting values for these controls in my "addButtonPressed" method with:
//ad is AppDelegate - declared in interface as AppDelegate* ad;
NSPathControl* pcSource = [ad pcSource];
NSPathControl* pcDestination = [ad pcDestination];
NSTextField* tfBackupAmount = [ad tfBackupAmount];

My own method isn't being found by the compiler

I recently started learning Objective-C and Cocos-2D. I tried to define my own method for automating the creation of sprites.
I added my own class where I'll create other automation methods as well. Anyhow my .h file looks like this:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface ActionsClass : CCNode {
}
#property (nonatomic, strong) CCSprite* createSprite;
#property (nonatomic, strong) CCSprite* spriteName;
#property (nonatomic, strong) NSString* pngName;
#property (nonatomic) CGPoint* spriteCoordinate;
- (CCSprite *)createSprite: (CCSprite *)spriteName: (NSString *)pngName: (CGPoint *)spriteCoordinate;
#end
And the .m is:
#import "ActionsClass.h"
#implementation ActionsClass
#synthesize createSprite = _createSprite;
#synthesize spriteName = _spriteName;
#synthesize pngName = _pngName;
#synthesize spriteCoordinate = _spriteCoordinate;
- (CCSprite *)createSprite: (CCSprite *)spriteName: (NSString *)pngName: (CGPoint *)spriteCoordinate
{
if (!_createSprite)
{
_createSprite = [[CCSprite alloc] init];
_spriteName = [CCSprite spriteWithFile:_pngName];
_spriteName.position = ccp(_spriteCoordinate->x, _spriteCoordinate->y);
[self addChild:_spriteName];
}
return _createSprite;
}
#end
In the main .m file where I want to call the method:
[self createSprite: saif: #"saif.png": ccp(100,100)];
This would give the warning that xcode didn't find the instance method createSprite and defaults it to id
Thanks a lot and sorry if the font or the formatting of the question aren't super neat.
Your method declaration is wrong, so you wont be able to call it.
It should be:
- (CCSprite *)createSprite:(CCSprite *)spriteName pngName:(NSString *)pngName coord:(CGPoint *)spriteCoordinate;
And called like:
[self createSprite:someSprite pngName:somePNGName coord:someCoord];
Edit: I didn't see that you were trying to call this from another class. To do that you will need to import the ActionsClass header file, and call this method on an instance of ActionsClass, e.g.
ActionsClass *actionsClassObject = [[ActionsClass alloc] init];
[actionsClassObject createSprite:someSprite pngName:somePNGName coord:someCoord];

Synthesize property to a Base class' ivar

I have a hierarchy of model objects which I will be displaying on different type of UITableViewCell subclasses. All decision is made on the fly as to which model object should be used and corresponding UITableViewCell subclass' object is spawned and then set the model object to the UITableViewCell's subclass object so that it can fetch values from it.
My UITableViewCell hierarchy is something like this:
The base class Cell hierarchy:
#interface BaseCell : UITableViewCell
{
Base *baseObj_;
}
#end
The subclass of cell hierarchy:
#interface DerivedCell : BaseCell
{
}
#property (nonatomic, retain) Derived *derivedObject;
#end
#implementation DerivedCell
#synthesize derivedObject = baseObj_;
#end
The base class of Model object:
#interface Base : NSObject
{
NSString *title_;
}
#property (nonatomic, retain) NSString *title;
#end
The subclass of model hierarchy
#interface Derived : Base
{
NSString *detailedText_;
}
#property (nonatomic, retain) NSString *detailedText;
#end
When I do so, I am having errors in this line:
#synthesize derivedObject = baseObj_;
Which reads:
Property 'derivedObject' attempting to use ivar 'baseObj_' declared in super class BaseCell.
Type of property 'derivedObject' (Derived*) does not match type of ivar 'baseObj_' ('Base * __strong')
I want to use properties and synthesize them so that I can leverage the uses of properties (like using dot notation etc.). I have for now used accessors and setters which solves the problem:
#interface DerivedCell : BaseCell
{
}
-(Derived*)derivedObject;
-(void)setDerivedObject:(Derived*)newDerivedObject;
#end
But I was just wondering if I could somehow fix these errors to use the properties only.
Thanks,
Raj
Try the below code I have modified your code a bit as shown below
Since you can assign class Base object to class Derived in #synthesize, it can be achieved by this way, I know you have tried it already, I have tried it with the below code and able to access the variables with dot, try the below code and let me know if it is not working
#interface DerivedCell : BaseCell
{
Derived *derivedObject;
}
#property (nonatomic, retain) Derived *derivedObject;
#end
#implementation DerivedCell
#dynamic derivedObject;
- (void)setDerivedObject:(Base *)baseObj {
if (self.derivedObject == nil) {
derivedObject = [[Derived alloc] init];
}
derivedObject.detailedText = baseObj.title;
}
- (Derived *)derivedObject {
return derivedObject;
}
#interface Derived : Base
{
NSString *detailedText_;
}
#property (nonatomic, retain) NSString *detailedText;
#end
#implementation Derived
#synthesize detailedText = detailedText_;
#end
#interface BaseCell : UITableViewCell
{
Base *baseObj_;
}
#property (nonatomic, retain) Base *baseObj;
#end
#implementation BaseCell
#synthesize baseObj = baseObj_;
#end
#interface Base : NSObject
{
NSString *title_;
}
#property (nonatomic, retain) NSString *title;
#end
#implementation Base
#synthesize title = title_;
#end
Base *b = [[Base alloc] init];
b.title = #"Hello Raj";
BaseCell *bc = [[BaseCell alloc] init];
bc.baseObj = b;
DerivedCell *dc = [[DerivedCell alloc] init];
dc.derivedObject = b;
NSLog(#"Derive dc %#", dc.derivedObject.detailedText);
Another Solution which I have provided has an issue when I checked it
#interface BaseCell : UITableViewCell
{
NSString *baseTitle_;
}
#property (nonatomic, retain) NSString *baseTitle;
#end
#implementation BaseCell
#synthesize baseTitle = baseTitle_;
#end
#interface DerivedCell : BaseCell
{
NSString *derivedTitle_;
}
#property (nonatomic, retain) NSString *derivedTitle;
#implementation DerivedCell
#synthesize derivedTitle = baseTitle;
#end
When I created instance for the class and as shown below
DerivedCell *dCell = [[DerivedCell alloc] init];
dCell.baseTitle = #"Hello";
NSLog(#"%#",dCell.baseTitle);//Output was Hello
NSLog(#"%#",dCell.derivedTitle);//Output was (null)
It didn't assign the value to derivedTitle, If it is working for you please let me know
Another solution with memory referncing
#interface BaseCell : UITableViewCell
{
NSMutableString *baseTitle_;
}
#property (nonatomic, retain) NSMutableString *baseTitle;
#end
#implementation BaseCell
#synthesize baseTitle = baseTitle_;
#end
#interface DerivedCell : BaseCell
{
}
#property (nonatomic, retain) NSMutableString *derivedTitle;
#end
#implementation DerivedCell
#synthesize derivedTitle;
- (id) init
{
if ( self = [super init] )
{
baseTitle_ = [[NSMutableString alloc] init];
derivedTitle = baseTitle_;
}
return self;
}
#end
DerivedCell *dCell = [[DerivedCell alloc] init];
[dCell.baseTitle appendString:#"Hello"];
NSLog(#"baseTitle : %#",dCell.baseTitle);
NSLog(#"derivedTitle :%#",dCell.derivedTitle);
Console Output baseTitle : Hello derivedTitle :Hello
One pattern I've used for situations like this is to re-declare the property in a category on the derived class. The one structural change this approach requires from the code you posted is that it requires a same-named property (or equivalent getter/setter methods) to be defined in the base class. Consider the following snippet:
#interface BaseModel : NSObject
#end
#interface DerivedModel : BaseModel
#end
#interface BaseCell : UITableViewCell
{
BaseModel *baseObj_;
}
#property (nonatomic, retain) BaseModel *modelObject;
#end
#interface DerivedCell : BaseCell
#end
#interface DerivedCell (DowntypedPropertyCategory)
#property (nonatomic, retain) DerivedModel *modelObject;
#end
#implementation BaseModel
#end
#implementation DerivedModel
#end
#implementation BaseCell
#synthesize modelObject = baseObj_;
#end
#implementation DerivedCell
#end
In this pattern, the base class declares the iVar and the base-typed property, and synthesizes the implementation. The derived class declares the downcast-typed property in a category. Being in a category, the compiler won't force you to implement methods for that property. This gets you out of trying to synthesize against a superclass's iVar, instead relying on implementations that exist in the superclass, but declaring them to be of a different type. At runtime, the runtime will just end up calling the superclass methods (since Obj-C method dispatch is based on selector only, and does not have multiple dispatch.) As a result, clients of these properties can do stuff like this without any compile time warnings or errors:
#interface UnrelatedObject : NSObject
#end
#implementation UnrelatedObject
- (void)unrelatedMethod: (DerivedCell*)dc
{
DerivedModel* dm = dc.modelObject;
NSLog(#"dm: %#", dm);
}
#end
Again, the catch/minor difference is that in order for this to work, the base class must define a property of the same name (or equivalent getter/setter methods). That said, the property/methods in the base class could be declared (or in the case of methods, NOT even delayed) and defined in the base class's implementation file only, and thus would not be visible to other files merely including the header.
One other note: by using this approach you're missing out on compile time checks for things like mismatch between the property specifiers ([nonatomic|atomic], [readonly|readwrite], [assign|retain|copy]). I've found this pattern incredibly useful, but there are some potential pitfalls to keep an eye out for.
I hope I understand the question correctly, how about typing the model as id?
#interface BaseCell : UITableViewCell
#property(retain, nonatomic) id model;
#end
#implementation BaseCell
#synthesize model;
#end
Then the derived cells can use whatever model classes they want.
When you initialize an instance variable through synthesize, that variable is not accesible from any class that may inherit it.
It looks like you may have been trying to point synthesize to a public instance variable and I'm not sure if that is possible. It may be trying to declare a new variable with the same name which I'm sure would generate some compiler warnings at the least since that new declaration would hide an existing one and is less accessible.
You could simply write your own getter and setter to expose the instance variable.
- (Base *) baseObj {
return _baseObj;
}
- (void) setBaseObj:(Base *)val {
if( val != _baseObj ) {
[_baseObj release];
_baseObj = [val retain];
}
}
Hope this helps!