Pass data between objects - objective-c

I have a variable in a class, NSNumber. I want to pass the value of this var to another class var. The problem is that I release the object of the first class and obtain an error message when I try to set the value of the second class var.
In C++ this is so easy to do. But here with memory management and pointers confused me so much.
Solution code, for testing:
#import <Foundation/Foundation.h>
#interface A : NSObject
{
NSNumber *a;
}
#property (nonatomic, retain) NSNumber *a;
#end
int main(int argc, char *argv[])
{
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
A *instance1 = [[A alloc] init];
A *instance2 = [[A alloc] init];
[instance1 setA:[NSNumber numberWithFloat:5.43f]];
instance2.a = [instance1.a copy];
[instance1 release];
NSLog(#"Valor de la que sigue viva, parte2: %#", instance2.a);
[instance2 release];
[p release];
[pool drain];
return 0;
}

You should use a retain property or copy the instance variable:
#interface A {
NSNumber *a;
}
#property (nonatomic, retain) NSNumber *a;
#end
...
A *instance1 = [[A alloc] init];
A *instance2 = [[A alloc] init];
instance1.a = instance2.a;
//or
instance2.a = [instance1.a copy];
Read some docs about retain-counted memory management which is what Objective-C uses.

Related

Why weak property of associated object is not nilled out if I call its getter?

Though it's kind of stupid in 2020 that I'm still asking question about ObjC, please be patient and considerate...
I'm reading the source code of BloksKit and ran into a weird situation.
#import <objc/runtime.h>
#interface _WeakAssociatedObjectWrapper : NSObject
#property (nonatomic, weak) id object;
#end
#implementation _WeakAssociatedObjectWrapper
#end
#interface NSObject (AddWeak)
#end
#implementation NSObject (AddWeak)
- (void)setWeakProp:(id)weakProp {
_WeakAssociatedObjectWrapper *wrapper = objc_getAssociatedObject(self, #selector(weakProp));
if (!wrapper) {
wrapper = [[_WeakAssociatedObjectWrapper alloc] init];
objc_setAssociatedObject(self, #selector(weakProp), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
wrapper.object = weakProp;
}
- (id)weakProp {
id value = objc_getAssociatedObject(self, _cmd);
if ([value isKindOfClass:_WeakAssociatedObjectWrapper.class]) {
return [(_WeakAssociatedObjectWrapper *)value object];
}
return value;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
{
NSObject *prop = [[NSObject alloc] init];
[obj setWeakProp:prop];
[obj weakProp]; // *Weird!!
}
NSLog(#"Now obj.weakProp = %#", [obj weakProp]);
}
return 0;
}
This code is adding a weak associated object for category.(BlocksKit does so)
Note the *Weird!! line. If this line is commented out, then it prints (null), which is reasonable since prop is deallocated outside the {} scope. On the other side, if not commented out, it prints <NSObject: 0xxxxx>, which indicates that prop is somehow retained by someone(Or any other reason?).
What is happening here??! (BlocksKit behaves the same!)
Environment: XCode 10.3
This is a feature. For the case (and any similar)
[obj weakProp];
by properties/accessors naming convention ARC returns autoreleased instance, so in your case #autoreleasepool holds it and testing as below can show this.
int main(int argc, const char * argv[]) {
NSObject *obj = [[NSObject alloc] init];
#autoreleasepool {
{
NSObject *prop = [[NSObject alloc] init];
[obj setWeakProp:prop];
[obj weakProp]; // *Weird!!
}
NSLog(#"Now obj.weakProp = %#", [obj weakProp]);
}
NSLog(#"After autoreleased >> obj.weakProp = %#", [obj weakProp]);
return 0;
}

Objective-C addObject seems to put object into all array indices

I am trying to learn how to make simple classes.
So far I am not getting the results expected using addObject and my class.
Here is what I have:
In my view controller:
#import "onoffclass.h"
In its viewDidLoad:
NSMutableArray *inTable;
onoffclass *therec;
onoffclass *readrec;
inTable = [NSMutableArray array];
therec = [[onoffclass alloc]init];
readrec = [[onoffclass alloc]init];
for (int lop=0;lop<3;lop++){
therec.parsedID = [NSString stringWithFormat:#"%i",lop];
[inTable addObject:therec];
NSLog(#"lop=%i onoff.parsedID=%#",lop,therec.parsedID);
for (int z=0;z<[inTable count];z++){
readrec = inTable[z];
NSLog(#" inTable[%i] parsedID=%#",z,readrec.parsedID);
}
}
In my onoffclass.h:
#interface onoffclass : NSObject
#property NSString *parsedID;
#property NSString *parsedOn;
#property NSString *parsedOff;
#property NSString *parsedAdj;
#property NSString *parsedRoom;
#property NSString *parsedBuilding;
#property NSString *parsedWho;
#property NSString *parsedInfo;
#property NSString *parsedBillable;
-(onoffclass*)initWithSomeString: (NSString*)blah AndSomeNum: (int)num;
-(NSString*)description;
#end
In my onoffclass.m:
#import <Foundation/Foundation.h>
#import "onoffclass.h"
#implementation onoffclass {
NSString *_parsedID;
NSString *_parsedOn;
NSString *_parsedOff;
NSString *_parsedAdj;
NSString *_parsedRoom;
NSString *_parsedBuilding;
NSString *_parsedWho;
NSString *_parsedInfo;
NSString *_parsedBillable;
}
-(onoffclass*)initWithSomeString: (NSString*)blah AndSomeNum: (int)num {
self = [super init];
_parsedID = blah;
_parsedOn = #"on";
_parsedOff = #"off";
_parsedAdj = #"adj";
_parsedRoom = #"room";
_parsedBuilding = #"building";
_parsedWho = #"who";
_parsedInfo = #"info";
_parsedBillable = #"billable";
return self;
}
-(NSString*)description {
return [NSString stringWithFormat: #"%#", _parsedID];
}
#end
Here is the output:
lop=0 onoff.parsedID=0
inTable[0] parsedID=0
lop=1 onoff.parsedID=1
inTable[0] parsedID=1
inTable[1] parsedID=1
lop=2 onoff.parsedID=2
inTable[0] parsedID=2
inTable[1] parsedID=2
inTable[2] parsedID=2
Why does it appears that addObject is updating all array indices and how do I fix this?
Thanks,
Dale
You are creating one instance of onoffclass (by the way class names should start with a capital letter) then you are adding the same instance again and again in the loop. Since classes are reference types changing a property affects all occurrences of the same instance.
Solution is to put the line to create an instance in the loop
for (int lop = 0; lop < 3; lop++) {
therec = [[onoffclass alloc] init];
...

Set readonly attribute in ObjC

Is there a way to set a value to readonly attribute in Objective-C?
I actually don't care how nasty the code is unless it isn't stable anymore.
Never mind my comment, here's the two ways you do it:
#interface Grimley : NSObject
#property (readonly, copy) NSString * blabber;
#property (readonly, copy) NSString * narwhal;
- (id) initWithBlabber:(NSString *)newBlabber;
#end
#implementation Grimley
#synthesize blabber;
#synthesize narwhal = unicorn;
- (id) initWithBlabber:(NSString *)newBlabber {
self = [super init];
if( !self ) return nil;
// Any object can of course set its own ivar regardless
// of how the property it backs is declared.
blabber = [newBlabber copy];
// Refer to the _ivar_, not the property.
unicorn = #"One horn";
return self;
}
#end
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Grimley * g = [[Grimley alloc] initWithBlabber:#"Excelsior"];
// This is how you get around the property.
[g setValue:#"Nimitz" forKey:#"blabber"];
// Again, use the name of the variable, not the property
[g setValue:#"Pearly horn" forKey:#"unicorn"];
NSLog(#"%#", [g blabber]);
NSLog(#"%#", [g narwhal]);
[g release];
[pool drain];
return 0;
}

Can't access properties of returned objects?

//SomeObject.h
#import <Foundation/Foundation.h>
#interface SomeObject : NSObject {
}
#property NSInteger aProperty;
#end
//main.m
#import <Foundation/Foundation.h>
#import "SomeObject.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:[[[SomeObject alloc] init] autorelease] forKey:#"key1"];
[dictionary setObject:[[[SomeObject alloc] init] autorelease] forKey:#"key2"];
[dictionary objectForKey:#"key1"].aProperty = 5; //Error HERE
[dictionary release];
[pool drain];
return 0;
}
But on that line XCode gives me these errors:
error: Semantic Issue: Member reference type 'struct objc_object *' is a pointer; maybe you meant to use '->'?
error: Semantic Issue: No member named 'aProperty' in 'struct objc_object'
Can't I access a property of a returned object? (I mean, without directly calling the setter method)
You need to cast the returned object:
((SomeObject*)[dictionary objectForKey:#"key1"]).aProperty = 5;
or:
[(SomeObject*)[dictionary objectForKey:#"key1"] setAProperty: 5];
or:
SomeObject* obj = [dictionary objectForKey:#"key1"];
obj.aProperty = 5;

Not sure why I have "EXC Bad Access" error

I've programmed for a while in Java and .Net, but never really used C or Objective C. I'm still trying to understand a few concepts. I was working on a simple program just to see how I can make an array of structures. Which I believe I got right. I'm having a hard time figuring out how to access the subclasses and store values to the subclasses I created.
I'm guessing I'm getting the error because of my use of scanf. Can anyone offer any help?
Here's what I have so far.
#import <Foundation/Foundation.h>
//Player Prototype: Stores name and wins so far. It can also print out the name and wins
#interface Player : NSObject
{
NSString *name; //Player name
NSInteger wins; //Player wins
NSInteger losses; //Player losses
NSInteger bp; //extra value for anything I might need in the future.
}
#property (retain, nonatomic) NSString *name;
#property NSInteger wins;
#property NSInteger losses;
#property NSInteger bp;
#end
//Next part
#implementation Player
#synthesize name;
#synthesize wins;
#synthesize losses;
#synthesize bp;
#end
//Brackets
#interface Bracket : NSObject
{
NSMutableArray *playerarray;
Player *addplayer;
}
#property (retain, nonatomic) NSMutableArray *playerarray;//array of players
#property (retain, nonatomic) Player *addplayer;//player and data
-(void) SetUp;
#end
//Starting Bracket, working with only 8. Later moving up to 32
#implementation Bracket
#synthesize playerarray;
#synthesize addplayer;
-(void) SetUp;//sets up the array
{
int i;//counting fun!
playerarray = [[NSMutableArray alloc] init];//initialize a bracket
for(i = 0; i < 8; i++)//To add the players
{
Player *addplayerx = [Player new];//New instance of Player
NSString *p;//Not sure if I need two of them.
NSString *tempname = #"bye";
NSLog(#"Player %d Name:", i);
scanf("%s",&p);
tempname = p;
NSLog(#"%s", tempname);
addplayerx.name = p;
NSLog(#"%s", addplayerx.name);
addplayerx.wins = 0;
addplayerx.losses = 0;
addplayerx.bp = 0;
[playerarray addObject: addplayerx];
[addplayerx release];
[p release];
}
}
#end
//End function
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Bracket *starting = [Bracket new];
[starting SetUp];
[pool drain];
return 0;
}
You can't scanf() into an NSString. You need to scan into a regular C string (make sure you allocate memory for it), and then you can construct the NSString from that using stringWithUTF8String:, or something along those lines.
Don't guess: run the application under the debugger, and when it crashes, examine the backtrace. You can also look at the backtraces in ~/Library/Logs/DiagnosticReports/foo.crash.
What are you trying to do, read data line-by-line from a file? It would be much easier to just use text = [NSString stringWithContentsOfFile:path] then split text on all newline characters:
NSCharacterSet *newlines = [NSCharacterSet newlineCharacterSet];
NSArray *lines = [text componentsSeparatedByCharactersInSet:newlines];
You can then just loop across and grab the player names:
NSMutableArray *players = [NSMutableArray arrayWithCapacity:[lines count]];
NSString *whitespace = [NSCharacterSet whitespaceCharacterSet];
for (NSString *line in lines) {
NSString *name = [line stringByTrimmingCharactersInSet:whitespace];
Player *player = [[[Player alloc] init] autorelease];
player.name = name;
[players addObject:player];
}