Passing a pointer by reference to class and using it - iphone

I am trying to pass a pointer by reference to an object from class A to class B. In class B I want to assign this pointer to a ivar and read and write to it.
This is the code that gives me errors (does not matter what errors). This is my first try with pointers so please correct my understanding.
Class A
//This is the parameter I would like to pass as a pointer and be able to manipulate from class B
NSString *name = #"Cyprian";
-(void)passAParameter{
ClassB *classB = [[ClassB alloc] initWithAPointer:&name];
...
}
Class B
// ClassB.h
#interface ClassB{
NSString **nameFromClassA;
}
#property(nonatomic,assign)NSString **nameFromClassA;
-(id)initWithAPointer:(NSString **)name;
// ClassB.m
#implementation ClassB
#synthesize nameFromClassA;
-(id)initWithAPointer:(NSString **)name{
*nameFromClassA = *name;
}
//Print the name
-(void)printName{
NSLog(#"Name: %#", *nameFromClassA);
}
//Will this change the name in class A?
-(void)changeNameInClassA:(NSString* newName){
*nameFromClassA = newName;
}

Please, do not use double pointers here. You shouldn't handle things like that.
This is a simpler approach:
In the ClassA instance:
-(void)passAParameter{
NSString *name = #"Cyprian";
ClassB *classB = [[ClassB alloc] initWithAPointer:name];
...
}
While you define ClassB this way:
ClassB.h:
#interface ClassB{
NSString *nameFromClassA;
}
#property(nonatomic,retain) NSString *nameFromClassA; // Retaining it will give you less headaches
-(id)initWithAPointer:(NSString *)name;
#end
ClassB.m:
#implementation ClassB
#synthesize nameFromClassA;
// You should release all retained object when deallocating self
- (void) dealloc {
[nameFromClassA release];
nameFromClassA = nil;
[super dealloc];
}
-(id)initWithAPointer:(NSString *)name{
if ((self = [super init])) { // Always init the object from super!
self.nameFromClassA = name; // Retain the object calling self.
}
return self;
}
//Print the name
-(void)printName{
NSLog(#"Name: %#", nameFromClassA);
}
//Will this change the name in class A?
-(void)changeNameInClassA:(NSString* newName){
self.nameFromClassA = newName; // Retain it calling self.
}
#end

The assignment in your initWithAPointer: method should be just:
nameFromClassA = name;
That said, this code pattern smells of a bad design. What high-level goal is it that you're trying to accomplish?

Related

Is only one release is needed in my Objective C code?

For some reason I can't use arc, so in my code below..
Foo.h
#interface Foo : NSObject
#property (nonatomic, copy) NSString * string;
#end
Foo.m
#implementation Foo
#synthesize string=_string;
- (void) bar {
self.string = [NSString stringWithFormat:#"test1"];
self.string = [NSString stringWithFormat:#"test2"];
}
-(void) dealloc
{
[_string release];
[super dealloc];
}
#end
The bar method might not always be called, or they can be called multitime.
Is only one release in the dealloc is all needed?
Yes, since you are using properties so setter method will take care of releasing memory allocation.It will allocate memory as follows:
-(void)setValue:(NSString *)strValue
{
if(string)
{
[string release];
string = nil;
}
string = [strValue copy];
}
Is only one release in the dealloc is all needed?
Yes.
Explanation: the setter method releases the old object that was assigned to the property and retains the new one.

ARC Semantic Issue with simple protocol example?

I have just been trying something out with a quick test and I have a question, in the following code:
#protocol stuffieProtocol <NSObject>
#required
-(void)favouiteBiscuit;
#end
.
// DOG & TED ARE IDENTICAL, THEY JUST LIKE DIFFERENT BISCUITS
#interface Dog : NSObject <stuffieProtocol>
#property (strong, nonatomic) NSString *name;
#end
#implementation Dog
- (id)init {
return [self initWithName:#"Unknown"];
}
- (id)initWithName:(NSString *)name {
self = [super init];
if(self) {
_name = name;
}
return self;
}
- (void)whoAreYou {
NSLog(#"MY NAME IS: %# I AM A: %#", [self name], [self class]);
}
- (void)favouiteBiscuit {
NSLog(#"FAVOURITE BISCUIT IS: Costa Jam Biscuit");
}
#end
.
Dog *stuffie_001 = [[Dog alloc] initWithName:#"Dog Armstrong"];
Ted *stuffie_002 = [[Ted alloc] initWithName:#"Teddy Sullivan"];
NSArray *stuffieArray = #[stuffie_001, stuffie_002];
for(id<stuffieProtocol> eachObject in stuffieArray) {
[eachObject whoAreYou]; // << ERROR
[eachObject favouiteBiscuit];
}
My question is I am getting an error "ARC Semantic Issue: No known instance method for selector 'whoAreYou'"
If I prefix [eachObject whoAreYou]; with [(Dog *)eachObject whoAreYou]; then this works for all the iterations of the loop, but that just feels wrong as the all the objects in the array are not of type Dog.
What should I be prefixing this with to be correct?
Add
-(void) whoAreYou;
to your protocol. Then the compiler knows that eachObject in the loop responds to that method.
well, you declare eachObject as an ID
that's mean that the compiler doesn't know what kind of object it is
it just know that it implements the protocol stuffieProtocol, so surely it can respond to method: favouiteBiscuit
but it doesn't know if it can respond to method whoAreYou
you can do many thing to avoid this
the easiest is:
you could ask if eachObject can perform the selector whoAreYou, and in this case you perform that selector
if ([eachObject respondsToSelector:#selector(whoAreYou) ]) {
[eachObject performSelector:#selector(whoAreYou) ];
}
this way the compiler avoid to control if eachObject implement the method whoAreYou
it will be done at runtime, so if there a method whoAreYou in eachObject, then ok, it will be called
Another way could be to make a common superclass for both ted and dog
(e.g.
SuperClassOfTedAndDog <stuffieProtocol>
)
and declare method whoAreYou in that superclass, then in your for loop use that superclass instead of ID:
for(SuperClassOfTedAndDog* eachObject in stuffieArray) {
[eachObject whoAreYou];
[eachObject favouiteBiscuit];
}

Correct way to create/use a Singleton NSMutableArray for Xcode 4

I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...

Custom Object Initialization in Objective-C

I created a custom object in Objective-C. Now I want to create a custom initializer. The object has two properties, name and score. So my initializer is as follows:
- (id)initWithName:(NSString *)playerName {
if ((self = [super init])) {
self.name = [playerName retain];
self.score = [NSNumber numberWithInt:0];
}
return self;
}
Am I using retain here properly? Or can I just make it something like self.name = playerName;?
Furthermore, assume I want another initializer, but keep the initWithName:playerName the designated initializer. How would I make the second initializer call the first?
And for the last question, I know I need to override the - (id)init method too. However, what do I do there? Just assign test properties incase the class was initialized with init only?
Thank you!
Am I using retain here properly?
No you are not. You should either use
self.name = playerName;
as you suggested, or (as recommended by Apple)
name = [playerName copy];
It is not recommended to use accessors in -init because subclasses might override them.
Also, note that as NSString implements NSCopying you should use a copy property, not a retain property.
Furthermore, assume I want another initializer, but keep the initWithName:playerName the designated initializer. How would I make the second initializer call the first?
Using -init as an example (because you must override the super class's designated initialiser if your designated initialiser is not the same)
-(id) init
{
return [self initWithName: #"Some default value"];
}
you could keep self.name = playerName; if you have declared name as retained property in .h class and have also #synthesized in .m file.
For the initialization you could put the belwo two line of code in separate method.
-(void) initializeWithName:(NSString*) aName withNumber:(int) aNumber
{
self.name = aName;
self.score = [NSNumber numberWithInt:aNumber];
}
Lets you have three Initialization method.
- (id)initWithName:(NSString *)playerName {
if ((self = [super init])) {
[self initializeWithName:playerName withNumber:0]
}
return self;
}
- (id)initWithNumber:(int*) aNumber {
if ((self = [super init])) {
[self initializeWithName:nil withNumber:aNumber]
}
return self;
}
- (id)init{
if ((self = [super init])) {
[self initializeWithName:nil withNumber:0]
}
return self;
}
For what's it's worth to the rest of us newbies:
In normal languages, can simply define arguments when instantiating the class:
public final class MakeBed {
private var foo:Object;
public var bar:Array;
public function MakeBed(_foo:Object, _bar:Array) {
// Do stuff
foo = _foo;
bar = _bar;
}
}
Then when we want to instantiate the class it's as simple as:
var myBeadMaker:MakeBed = new MakeBed({}, []);
In objc everything is backasswards.
You can create your custom initializer similar to:
// These #properties go into the header.h file
#property (nonatomic, retain) NSString *foo;
#property (nonatomic, retain) NSString *bar;
// This is in your implimentation.m file
- (id) initWithInfo:(NSObject*)foo withBar:(NSArray *)bar {
_foo = foo;
_bar = bar;
}
Objc automatically "synthesizes" the getters and setters and automatically creates a new variable "blindly" using the same _name _but _with _an _underscore in front when you do the #property thing -- it's magic -- bordering on the "almost too helpful" side of things.
Handy for non-newbies, but incredibly confusing for newbies -- just believe that the getter and setter is made and that a _new _var _is _available.
And the clincher that everyone forgets to mention...
When you want to instantiate the class with your custom initializer you do this:
MakeBed myBedMaker = [[MakeBed alloc] initWithInfo:*foo withBar:*bar];

iPhone SDK: How/when should I release a UITableView delegate object?

I am using a custom class as the delegate and datasource on a UITableView. I'm doing (something like) this in my viewDidLoad method:
MyClass *myObject = [[MyClass alloc] init];
tableViewOutlet.delegate = myObject;
tableViewOutlet.dataSource = myObject;
Surely I need to decrease the retain count on myObject somewhere? But calling [myObject release] here has very bad results - the delegate gets destroyed before the table has finished doing its stuff.
I have tried
MyClass *myObject = [[[MyClass alloc] init] autorelease];
but it also has terrible consequences.
Do I have a memory leak here? If so, how and when do I release the delegate safely?
Your interface file:
#interface SomeClass: NSObject {
MyClass *myObject;
}
#property (nonatomic,retain) MyClass *myObject;
#end
Your implementation file:
#implementation SomeClass
#synthesize myObject;
-(void)dealloc {
// if you want to be safe, change tableViewOutlet properties...
// tableViewOutlet.delegate = nil;
// tableViewOutlet.dataSource = nil;
[myObject release]; // retain = 0
[super dealloc];
}
...
MyClass *obj = [[MyClass alloc] init]; // retain = 1
self.myObject = obj; // retain = 2
// NOTE: if you instead write: myObject = obj; **NO** retain msg will be sent.
// *not* what you want in this context.
tableViewOutlet.delegate = obj; // assign, so retain =2
tableViewOutlet.dataSource = obj; // assign, so retain = 2
[obj release]; // retain = 1
...
#end
make myObject an instance variable by declaring it in the #interface (.h file), then call...
[myObject release];
.. in your dealloc method.