Class Composition Error? - objective-c

I wonder if someone can explain where I am going wrong here, I am creating 2 objects (car & engine) where the car object contains a pointer to the engine object. I know I am missing the obvious or just making some silly mistake, but I can't quite put my finger on it.
NB: the code all works, except for the line that is comment ERROR.
// INTERFACE ------------------------------------------------------- **
#interface EngineClass : NSObject {
}
#end
#interface CarClass : NSObject {
EngineClass *engine;
}
- (void)setEngine:(EngineClass *)value;
#end
// IMPLEMENT ------------------------------------------------------- **
#implementation CarClass
- (void)setEngine:(EngineClass *)newEngine {
if (engine != newEngine) {
[engine release];
engine = [newEngine copy];
}
}
#end
#implementation EngineClass
#end
// MAIN ------------------------------------------------------------ **
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CarClass *newCar_001;
EngineClass *newEngine_001;
newCar_001 = [[CarClass alloc] init];
newEngine_001 = [[EngineClass alloc] init];
[newCar_001 setEngine: newEngine_001]; // ERROR
// Clean up
[newCar_001 release];
[newEngine_001 release];
[pool drain];
return 0;
}
// END ------------------------------------------------------------- **
The ERROR is ....
run
2009-09-22 13:41:05.483 cocoa_engine_TEST[8606:a0f]
2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f]
2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f] -[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0
2009-09-22 13:41:05.486 cocoa_engine_TEST[8606:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0'
cheers -gary-

From the docs for the copy method:
This is a convenience method for
classes that adopt the NSCopying
protocol. An exception is raised if
there is no implementation for
copyWithZone:.
Have you implemented copyWithZone?
And why copy engine when you could just retain?
- (id)copyWithZone:(NSZone *)zone {
EngineClass *engineCopy = [[EngineClass allocWithZone: zone] init];
// copy variables here, deep or shallow
return engineCopy;
}
It returns a retained object, as copy methods should.

Related

Error : unrecognized selector sent to class

I am a complete noob when it comes to Objective C (or even for OOP for that matter). Here is what I am trying to do
AInterface.m
#implementation AInterface
- (BOOL)getParam:(NSData **)a param1:(NSData**)param1 param2:(NSData**)param2
{
//Do a bunch of things
return bool;
}
#end
AInterface.h
#interface AInterface : NSObject
- (BOOL)getParam:(NSData **)a param1:(NSData**)param1 param2:(NSData**)param2;
+ (instancetype) inst;
#end
testMain.m()
int main()
{
Bool result = NO;
NSData *a = Nil;
NSData *b = Nil;
NSData *c = Nil;
result = [[AInterface inst] getParam:(NSData **)&a param1:(NSData**)&a param2:(NSData**)&b];
return result
}
When I run this though, I get an error saying failed:
caught "NSInvalidArgumentException", "+[AInterface inst]: unrecognized selector sent to class
Although you declared +inst method in #interface section your class does not have it implemented and that leads to runtime error. You need to add implementation to make it work, e.g.
#implementation AInterface
...
+ (instancetype)inst {
return [self new];
}
Your problem is that you don't have implementation of +inst in AInterface.m.
In your case inst would be something like:
[[AInterface alloc] init] but I'd just use [[AInterface alloc] init] instead of calling inst in the first place. Or [AInterface new], which stands for the same.
In general, the rest of your code is not idiomatic Objective-C.

NSObject can not access property and method

I have a very strange problem, I have two classes the first one is a sub class of NSObject class it contains a method that add an object to its array. See the code below:
#import "portfolio.h"
#implementation portfolio
-(void) addStockObject:(stockHolding *)stock
{
[self.stocks addObject:stock ];
}
+(portfolio *) alloc
{
return [self.superclass alloc];
}
-(portfolio *) init
{
self.stocks=[[NSMutableArray alloc]init];
return self;
}
-(NSString *)getCurrentValue
{
stockHolding *stockInArray;
float currentValue=0.0;
for (NSInteger *i=0; i<[self.stocks count]; i++) {
stockInArray = [self.stocks objectAtIndex:i];
currentValue+=stockInArray.currentValue;
}
return [NSString stringWithFormat:#"Current Value: %f",currentValue];
}
#end
so when i call the method -(void) addStockObject:(stockHolding *)stock, i get the following error(during runtime):
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NSObject addStockObject:]: unrecognized selector
sent to instance 0x8b48d90'
The calling code is:
p=[[portfolio alloc]init];
[p addStockObject:s];
portfolio *p;
anyone can tell me what is wrong?
the other class has a property and it seems that it can not access it during compile time.
I'm really confused.
Thank you,
missa
First, never override +(portfolio *) alloc.
Second, init methods must call another init method and you must always check self for nil before setting ivars. Apple recommends against using properties to set ivars in init methods and init methods should always return instancetype in compilers that support it or id in those that don't.
-(instancetype) init
{
self = [super init];
if (self)
{
_stocks = [[NSMutableArray alloc] init];
}
return self;
}

Objective-C Runtime - Run Code at Deallocation of Any Object

I was reading this article by Jeff Kelley and trying to do the same. However the code was written before ARC was adopted and now fails to compile.
http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/
The main problem is in this part of the printout, some casting errors and then blocked release messages. I found it to be a very interesting example but I can't seem to get it to work.
The problems are:
0. Autosynthesized property 'block' will use synthesized instance variable '_block', not existing instance variable 'block' on the #implementation JKBlockExecutor
1. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast and Cast of C pointer type 'void *' to block pointer type 'typeof (aBlock)' (aka 'void (^__strong)(void)') requires a bridged cast" on the block = Block_copy(aBlock); line
2. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast on Block_release(block);
typedef void (^voidBlock)(void);
#interface JKBlockExecutor : NSObject {
voidBlock block;
}
#property (nonatomic, readwrite, copy) voidBlock block;
- (id)initWithBlock:(voidBlock)block;
#end
#implementation JKBlockExecutor
#synthesize block;
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
block = Block_copy(aBlock);
}
return self;
}
- (void)dealloc
{
if (block != nil) {
block();
Block_release(block);
}
[super dealloc];
}
#end
This is where he creates a category on NSObject.
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block;
#end
#implementation NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
[executor release];
}
}
#end
This is how you execute the example.
NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];
[foo release];
Or another way to get other information.
NSObject *foo = [[NSObject alloc] init];
__block id objectRef = foo;
[foo runAtDealloc:^{
NSLog(#"Deallocating foo at address %p!", objectRef);
}];
[foo release];
Can this code be fixed somehow? I took out all the release messages to no avail.
Code below builds and works (or at least seems so), and prints "Deallocating foo!" when I expect it to print it. Part 1:
typedef void (^voidBlock)(void);
#interface JKBlockExecutor : NSObject {
voidBlock block;
}
#property (nonatomic, readwrite, copy) voidBlock block;
- (id)initWithBlock:(voidBlock)block;
#end
#implementation JKBlockExecutor
#synthesize block = block;
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
block = [aBlock copy];
}
return self;
}
- (void)dealloc
{
if (block != nil) {
block();
block = nil;
}
}
#end
Part 2:
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block;
#end
#implementation NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
}
}
#end
Testing if it works:
#autoreleasepool {
NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];
}
EDIT
Changed Block_release(block); to block = nil;
If you want to know more about the code below ,please go to Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object
Part 1:create one class: the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
typedef void (^voidBlock)(void);
#interface CYLBlockExecutor : NSObject
- (id)initWithBlock:(voidBlock)block;
#end
// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
#import "CYLBlockExecutor.h"
#interface CYLBlockExecutor() {
voidBlock _block;
}
#implementation CYLBlockExecutor
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
_block = [aBlock copy];
}
return self;
}
- (void)dealloc
{
_block ? _block() : nil;
}
#end
Part 2:core code:use runtime to realize cyl_runAtDealloc method
// CYLNSObject+RunAtDealloc.h file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method
#import "CYLBlockExecutor.h"
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (CYLRunAtDealloc)
- (void)cyl_runAtDealloc:(voidBlock)block;
#end
// CYLNSObject+RunAtDealloc.m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method
#import "CYLNSObject+RunAtDealloc.h"
#import "CYLBlockExecutor.h"
#implementation NSObject (CYLRunAtDealloc)
- (void)cyl_runAtDealloc:(voidBlock)block
{
if (block) {
CYLBlockExecutor *executor = [[CYLBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
}
}
#end
How to use :
#import "CYLNSObject+RunAtDealloc.h"
then
NSObject *foo = [[NSObject alloc] init];
[foo cyl_runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];

How can I make a deep copy in Objective-C?

I'm learning ios development and I'm confused with deep copying in Objective-C.
For example,I have three class below. Now I want to deep copy ClassA, can anybody teach me to finish the copy method?
A:
#interface ClassA : NSObject <NSCopying>
#property (nonatomic, assign) int aInt;
#property (nonatomic, retain) ClassB *bClass;
#end
B:
#interface ClassB : NSObject <NSCopying>
#property (nonatomic, assign) int bInt;
#property (nonatomic, retain) ClassC *cClass;
#end
C:
#interface ClassC : NSObject <NSCopying>
#property (nonatomic, assign) int cInt;
#property (nonatomic, copy) NSString *str;
#end
Following the explanation at http://www.techotopia.com/index.php/Copying_Objects_in_Objective-C
"This can be achieved by writing the object and its constituent elements to an archive and then reading back into the new object."
#implementation ClassA
- (id)copyWithZone:(NSZone*)zone{
NSData *buffer;
buffer = [NSKeyedArchiver archivedDataWithRootObject:self];
ClassA *copy = [NSKeyedUnarchiver unarchiveObjectWithData: buffer];
return copy;
}
#end
You should add the copyWithZone: method in each class you want to be copiable.
NB: I wrote this by hand, watch out for typos.
-(id) copyWithZone:(NSZone *) zone
{
ClassA *object = [super copyWithZone:zone];
object.aInt = self.aInt;
object.bClass = [self.bClass copyWithZone:zone];
return object;
}
-(id) copyWithZone:(NSZone *) zone
{
ClassB *object = [super copyWithZone:zone];
object.bInt = self.bInt;
object.cClass = [self.cClass copyWithZone:zone];
return object;
}
-(id) copyWithZone:(NSZone *) zone
{
ClassC *object = [super copyWithZone:zone];
object.cInt = self.cInt;
object.str = [self.str copy];
return object;
}
Objective-C on iOS doesn’t offer any direct language or library construct to switch between a shallow and a deep copy. Each class defines what it means to “get its copy”:
#implementation ClassA
- (id) copyWithZone: (NSZone*) zone
{
ClassA *copy = [super copyWithZone:zone];
[copy setBClass:bClass]; // this would be a shallow copy
[copy setBClass:[bClass copy]]; // this would be a deep copy
return copy;
}
#end
Of course you would have to do the same decision in ClassB and ClassC. If I am not mistaken, the usual semantics for a copy in Objective-C is to return a shallow copy. See also this question about copying arrays for more discussion of the topic.
I had custom classes with long lists of properties, so I iterated over them:
#interface MyClass : NSObject <NSCopying>
#import <objc/runtime.h>
-(id) copyWithZone: (NSZone *) zone {
MyClass *myCopy = [[MyClass alloc] init];
//deepCopy
unsigned int numOfProperties;
objc_property_t *properties = class_copyPropertyList([self class], &numOfProperties);
for (int i = 0; i < numOfProperties; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [[NSString alloc]initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[adressCopy setValue:[[self valueForKey:propertyName] copy] forKey:propertyName];
}
return myCopy;
}
All customClassProperties will need to implement this as well.
This could be of some help. The link shows how to do the deep copy using NSKeyedArchiver
http://iphonecodecenter.wordpress.com/2013/08/26/difference-between-shallow-copy-and-deep-copy/
Objective-C's copy and copyWithZone specifications are bogus and dangerous and should not be used.
--!-- At least not when used with ARC (Automatic Reference Counting) (2016-08-23) --!--
The code will lead to writing out of the bounds of memory / buffer overflows.
Instead I present a method to safely copy objects initAsShallowCopy and deepCopy.
See my test results in code below:
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
{
#public
NSMutableString* A_Name;
NSInteger A_NSInteger;
long int A_int;
float A_float;
}
-(id)init;
-(id)copyWithZone:(NSZone *) zone; // DON'T USE copy OR copyWithZone, unless you ignore Apple's guidelines and always make shallow copies in line with the correct example code here for initAsShallowCopy (but you return a copy instead of being a copy)
-(id)initAsShallowCopy:(ClassA *)original; // Correct way to make a shallow copy
-(void)deepCopy; // Correct way to make a deep copy (Call initAsShallowCopy first)
#end
#interface ClassB : ClassA
{
#public
NSMutableString* B_Name;
NSInteger B_NSInteger;
long int B_int;
float B_float;
}
-(id)init;
-(id)copyWithZone:(NSZone *) zone; // DON'T USE copy OR copyWithZone, unless you ignore Apple's guidelines and always make shallow copies in line with the correct example code here for initAsShallowCopy (but you return a copy instead of being a copy)
-(id)initAsShallowCopy:(ClassB *)original; // Correct way to make a shallow copy
-(void)deepCopy; // Correct way to make a deep copy (Call initAsShallowCopy first)
-(void)print;
#end
#interface ClassCWithoutCopy : NSObject
{
#public
NSMutableString* C_Name;
NSInteger C_NSInteger;
long int C_int;
float C_float;
}
-(id)init;
-(void)print;
#end
#implementation ClassA
-(id)init
{
if ( self = [super init] ) { // initialize NSObject
//A_Name = [[NSMutableString alloc] init];
//[A_Name setString:#"I am inited to A"];
A_Name = [NSMutableString stringWithString:#"I am inited to A"];
A_NSInteger = 1;
A_int = 1;
A_float = 1.0;
return self;
}
return nil;
}
/*
FROM https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/#//apple_ref/occ/instm/NSObject/copy
-- NSObject Class Reference --
- (id)copy
Discussion
This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is
no implementation for copyWithZone:.
NSObject does not itself support the NSCopying protocol. Subclasses must support the protocol and
implement the copyWithZone: method. A subclass version of the copyWithZone: method should send the message to super first,
to incorporate its implementation, unless the subclass descends directly from NSObject.
+ copyWithZone:
Discussion
This method exists so class objects can be used in situations where you need an object that conforms to the NSCopying protocol.
For example, this method lets you use a class object as a key to an NSDictionary object.
You should not override this method.
CONCLUSION
copy says we should incorporate the implementation of copyWithZone, while copyWithZone says we should not override it.. So what is it?
Looking at copyWithZone, we see that it is a class method (+), meaning it has not access to its instantiated members.
So maybe they mean, we should not override the class method (+), but we should implement its instance method -copyWithZone:
!!In any case we should not implement copy, because it is just made for convenience by Apple!!
FROM: https://developer.apple.com/library/tvos/documentation/Cocoa/Reference/Foundation/Protocols/NSCopying_Protocol/index.html
-- NSCopying --
Your options for implementing this protocol are as follows:
1) Implement NSCopying using alloc and init... in classes that don’t inherit copyWithZone:.
2) Implement NSCopying by invoking the superclass’s copyWithZone: when NSCopying behavior is inherited.
If the superclass implementation might use the NSCopyObject function, make explicit assignments to
pointer instance variables for retained objects.
3) Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.
CONCLUSION:
From 1) NSObject does not implement copyWithZone so any class that you make that should support copying should call [[Class alloc] init].
From 2) Any subclass of a copyable object should call [super copyWithZone:zone], but NOT [[Class alloc] init] !!!!!!
*/
-(id) copyWithZone:(NSZone *) zone
{
ClassA *CopiedObject = [[ClassA alloc] init];
if(CopiedObject){
CopiedObject->A_Name = [A_Name copy];
CopiedObject->A_NSInteger = A_NSInteger;
CopiedObject->A_int = A_int;
CopiedObject->A_float = A_float;
return CopiedObject;
}
return nil;
}
-(id)initAsShallowCopy:(ClassA *)original // Correct way to make a shallow copy
{
/* Why this has to be done like this:
It is very annoying to assign every variable explicitely.
However this has to be done, in order for ARC (Automatic Reference Counting) (2016-08-23) to work.
The compiler needs to be aware of any reference made to an object or reference cleared to an object in order to keep track of the
reference counts.
The danger is that when you add a variable to you class later on, you must not forget to update your initAsShallowCopy function and
possibly your DeepCopy function.
It would be much nicer if you could just do:
*self = *original;
But that gives compiler error:
/DeepCopyTest/main.m:135:9: Cannot assign to class object ('ClassA' invalid)
So therefore there is also no raw memory copy between objects,
so we are stuck with writing out each member variable explicitely.
*/
if ( self = [super init] ) { // initialize NSObject
A_Name = original->A_Name;
A_NSInteger = original->A_NSInteger;
A_int = original->A_int;
A_float = original->A_float;
return self;
}
return nil;
}
-(void)deepCopy; // Correct way to make a deep copy (Call initAsShallowCopy first)
{
/* Luckily now, we only have to duplicate the objects that require a deep copy.
So we don't have to write out all the floats, ints and NSIntegers, etcetera. Thus only the pointers (*) to objects.
*/
A_Name = [A_Name copy];
}
#end
#implementation ClassB
-(id)init
{
if ( self = [super init] ) { // initialize ClassA
B_Name = [NSMutableString stringWithString:#"I am inited to B"];
B_NSInteger = 2;
B_int = 2;
B_float = 2.0;
return self;
}
return nil;
}
-(id) copyWithZone:(NSZone *) zone
{
//ClassA *CopiedObject = [[ClassA alloc] init]; We are not a direct descendant from NSObject, so don't call alloc-init
// instead call the super copyWithZone
ClassB *CopiedObject = [super copyWithZone:zone]; /* Using ARC (Automatic Reference Counting) 2016-08-23:
THIS IS A MASSIVE BUFFER OVERFLOW/WRITING OUT OF BOUNDS RISK:
Since super now allocates the object, it will now only allocate an object of size ClassA
and effectively allocate too little memory for the ClassB. Unless memory allocation is upgraded to work with magic for
Objective-C, DON'T USE copy or copyWithZone!!!!
*/
if(CopiedObject){
CopiedObject->B_Name = [B_Name copy];
CopiedObject->B_NSInteger = B_NSInteger;
CopiedObject->B_int = B_int;
CopiedObject->B_float = B_float;
return CopiedObject;
}
return nil;
}
-(id)initAsShallowCopy:(ClassB *)original // Correct way to make a shallow copy
{
if ( self = [super initAsShallowCopy:original] ) { // initialize ClassA
B_Name = original->B_Name;
B_NSInteger = original->B_NSInteger;
B_int = original->B_int;
B_float = original->B_float;
return self;
}
return nil;
}
-(void)deepCopy; // Correct way to make a deep copy (Call initAsShallowCopy first)
{
/* Luckily now, we only have to duplicate the objects that require a deep copy.
So we don't have to write out all the floats, ints and NSIntegers, etcetera. Thus only the pointers (*) to objects.
*/
[super deepCopy];
B_Name = [B_Name copy];
}
-(void)print
{
NSLog(#"A_Name=\"%#\", A_NSInteger=%ld,A_int=%ld,A_float=%f",A_Name,A_NSInteger,A_int,A_float);
NSLog(#"B_Name=\"%#\", B_NSInteger=%ld,B_int=%ld,B_float=%f",B_Name,B_NSInteger,B_int,B_float);
}
#end
#implementation ClassCWithoutCopy
-(id)init
{
if ( self = [super init] ) { // initialize NSObject
C_Name = [NSMutableString stringWithString:#"I am inited to C"];
C_NSInteger = 3;
C_int = 3;
C_float = 3.0;
return self;
}
return nil;
}
-(void)print
{
NSLog(#"C_Name=\"%#\", C_NSInteger=%ld,C_int=%ld,C_float=%f",C_Name,C_NSInteger,C_int,C_float);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
ClassB *OriginalB;
ClassB *CopiedB;
#define USE_CORRECT_DEEP_COPY_AND_SHALLOW_COPY 1
#define USE_CLASSC_WITHOUT_COPY_TEST 0
#if(USE_CLASSC_WITHOUT_COPY_TEST)
ClassCWithoutCopy *OriginalC;
ClassCWithoutCopy *CopiedC;
OriginalC = [[ClassCWithoutCopy alloc] init];
CopiedC = [OriginalC copy]; /* Thread 1: signal SIGABRT: libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ClassCWithoutCopy copyWithZone:]: unrecognized selector sent to instance 0x100100450' */
//CopiedC = [ClassCWithoutCopy copyWithZone:nil]; /* DeepCopyTest/main.m:283:33: 'copyWithZone:' is unavailable: not available in automatic reference counting mode
*/
NSLog(#"OriginalC print:1");
[OriginalC print];
NSLog(#"CopiedC print:1");
[CopiedC print];
[OriginalC->C_Name appendString:#" and Appended as the original"];
OriginalC->C_NSInteger = 30;
OriginalC->C_int = 30;
OriginalC->C_float = 30.0;
NSLog(#"OriginalC print:2");
[OriginalC print];
NSLog(#"CopiedC print:2");
[CopiedC print];
#endif
#if(USE_CORRECT_DEEP_COPY_AND_SHALLOW_COPY)
OriginalB = [[ClassB alloc] init];
CopiedB = [[ClassB alloc] initAsShallowCopy:OriginalB];
NSLog(#"OriginalB print:1");
[OriginalB print];
NSLog(#"CopiedB print:1");
[CopiedB print];
[OriginalB->A_Name appendString:#" and Appended as the original"];
OriginalB->A_NSInteger = 10;
OriginalB->A_int = 10;
OriginalB->A_float = 10.0;
[OriginalB->B_Name appendString:#" and Appended as the original"];
OriginalB->B_NSInteger = 20;
OriginalB->B_int = 20;
OriginalB->B_float = 20.0;
NSLog(#"OriginalB print:2");
[OriginalB print];
NSLog(#"CopiedB print:2");
[CopiedB print];
// This works as expected: The values of OriginalB and CopiedB differ, but the shallow copied strings are the same.
// Now make a deep copy of CopiedB
[CopiedB deepCopy];
[OriginalB->A_Name appendString:#" and Appended twice as the original"];
OriginalB->A_NSInteger = 100;
OriginalB->A_int = 100;
OriginalB->A_float = 100.0;
[OriginalB->B_Name appendString:#" and Appended twice as the original"];
OriginalB->B_NSInteger = 200;
OriginalB->B_int = 200;
OriginalB->B_float = 200.0;
NSLog(#"OriginalB print:3");
[OriginalB print];
NSLog(#"CopiedB print:3");
[CopiedB print];
// This works as expected: The values of OriginalB and CopiedB differ and als the deep copied strings are different.
#else
OriginalB = [[ClassB alloc] init];
CopiedB = [OriginalB copy]; // Undefined behaviour. You will write unallocated memory
NSLog(#"OriginalB print:1");
[OriginalB print];
NSLog(#"CopiedB print:1");
/*[CopiedB print]; / * Thread 1: signal SIGABRT: libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ClassA print]: unrecognized selector sent to instance 0x10010ad60' */
NSLog(#"A_Name=\"%#\", A_NSInteger=%ld,A_int=%ld,A_float=%f",CopiedB->A_Name,CopiedB->A_NSInteger,CopiedB->A_int,CopiedB->A_float);
NSLog(#"B_Name=\"%#\", B_NSInteger=%ld,B_int=%ld,B_float=%f",CopiedB->B_Name,CopiedB->B_NSInteger,CopiedB->B_int,CopiedB->B_float); // Undefined behaviour. You will read unallocated memory
[OriginalB->A_Name appendString:#" and Appended as the original"];
OriginalB->A_NSInteger = 10;
OriginalB->A_int = 10;
OriginalB->A_float = 10.0;
[OriginalB->B_Name appendString:#" and Appended as the original"];
OriginalB->B_NSInteger = 20;
OriginalB->B_int = 20;
OriginalB->B_float = 20.0;
// This at least works: Changing Original, does not alter the values of Copy.
NSLog(#"OriginalB print:2");
[OriginalB print];
NSLog(#"CopiedB print:2");
NSLog(#"A_Name=\"%#\", A_NSInteger=%ld,A_int=%ld,A_float=%f",CopiedB->A_Name,CopiedB->A_NSInteger,CopiedB->A_int,CopiedB->A_float);
//NSLog(#"B_Name=\"%#\", B_NSInteger=%ld,B_int=%ld,B_float=%f",CopiedB->B_Name,CopiedB->B_NSInteger,CopiedB->B_int,CopiedB->B_float); // Undefined behaviour. You will read unallocated memory
/*[CopiedB->A_Name appendString:#" and Appended as the copy"]; / * Thread 1: signal SIGABRT: libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:' */
CopiedB->A_NSInteger = 100;
CopiedB->A_int = 100;
CopiedB->A_float = 100.0;
/*[CopiedB->B_Name appendString:#" and Appended as the copy"]; / * Thread 1: signal SIGABRT: libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'*/
CopiedB->B_NSInteger = 200; // Undefined behaviour. You will write unallocated memory
CopiedB->B_int = 200; // Undefined behaviour. You will write unallocated memory
CopiedB->B_float = 200.0; // Undefined behaviour. You will write unallocated memory
/* Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
DeepCopyTest(2376,0x7fff7edda310) malloc: *** error for object 0x10010ad98: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug */
NSLog(#"OriginalB print after modification of CopiedB:");
[OriginalB print];
NSLog(#"CopiedB print after modification of CopiedB:");
/*[CopiedB print];; / * Thread 1: signal SIGABRT: libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ClassA print]: unrecognized selector sent to instance 0x10010ad60' */
#endif
}
return 0;
}
PS-1: FROM:
https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/ObjectCopying.html
-- Object copying --
A deep copy duplicates the objects referenced while a shallow copy duplicates only the references to those objects. So if object A is shallow-copied to object B, object B refers to the same instance variable (or property) that object A refers to. Deep-copying objects is preferred to shallow-copying, especially with value objects.
NOTE:
This is unclear formulation, especially with the accompanied illustration, which suggests a wrong explanation.
This formulation makes it appear that two references to the same object count as a shallow copy. This is not true. It isn't a copy at all.
The clear formulation would be that:
-A shallow copy of an object has all the values and references copied from its parent, but is itself a unique object in memory.
-A deep copy of an object has all the values copied from its parent and is itself a unique object in memory, but all the references now reference to -deep themselves - copies of the original references objects.
Although the exact implementation of deep copying might not 100% give deep copies.
Objects that point to external references (suchs as a hardware item or graphics driver can't be duplicated, but only increase the reference count)
Some deep copying has no functional sense. An object might reference its window it is in, but it makes no sense to duplicate the window.
An object might also reference data that is considered immutable, so it would not be efficient to duplicate that.
PS-2: You could have give me the hint of ctrl-K before I tried to format all my code manually.
PS-3: Apple-Z (undo) undoes all my formatting instead of the last one and I can't redo it.

objective c Class code not executing? what is my problem?

Having some issues with code not executing within the classes I created and thought I initialized and implemented correctly here are all the files. There is a class with an array of another class. Then implemented in the code finally but for some reason none of the NSLog calls seem to execute except the one immediately before [mobdefs createTable] in the main code. All help appreciated...
// Mobdefs.h
#interface Mobdefs : NSObject {
#public NSMutableArray *mobInfo;
}
#property(retain) NSMutableArray *mobInfo;
-(void) createTable;
#end
// Mobdefs.m
#import "Mobdefs.h"
#import "Mobrec.h"
#implementation Mobdefs
#synthesize mobInfo;
- (id) init
{
mobInfo = [[NSMutableArray alloc] init];
return self;
}
-(void) addmobrec
{
MobRec *aNewMobRec = [[MobRec alloc] init];
aNewMobRec.mName=#"newbie";
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
NSLog(#"MobRec Added\n");
}
-(void) createTable
{
NSLog(#"Populating mob table.\n"); // *** THIS CODE NEVER SEEMS TO GET EXECUTED
}
#end
//main.h
Mobdefs *mobdef;
//main.m
NSLog(#"just before createTable call\n");
[mobdef createTable];
although the createTable code is called in the main the only NSLog output I get is the 'just before createtable...'
It doesn't seem that you have initialized mobdef. Add the following:
mobdef = [[Mobdefs alloc] init];
to your main.m before you invoke the method on it.
Objective-C silently ignore calls on nil, as mobdef would be initialized to initially.
are you allocating and initializing mobdef in main.m?