Crashing On CopyWithZone: Method - ios

I have created one class which is subclass of NSObject(nsme as GroupClass).In that class I have created one property which is belonging from 'id' ,like
#property(nonatomic,retain)id myObj;
Now I am standing on way where I have one mutable array,that array contains instances of my GroupClass.so I am getting one copy in similar way
GroupClass* objG=[array objectAtIndex:i];
now I want one another copy of objG.I searched .And I found NSCopying Protocol.So I added as delegate NSCopying to GroupClass and also added copyWithZone method.Here it is
-(id)copyWithZone:(NSZone *)zone
{
GroupClass *copy = [[[self class] allocWithZone: zone] init];
copy.myObj=[myObj copyWithZone: zone];
return copy;
}
Here I need deep copy.but it is always crashing after allocation line.Please help me.Thanking You.

Not all NSObject subclasses adopt the NSCopying protocol. The problem sounds like you are sending this message to an object which doesn't recognise it.
It doesn't matter that your GroupClass adopts NSCopying, that is not the problem. You are calling copyWithZone: on myObj, whatever that is.
This line of code:
copy.myObj=[myObj copyWithZone: zone];
Is almost certainly what is causing the crash.
EDIT
Not knowing what myObj is, I would recommend that if it is possible, and isn't a bad idea, that you subclass whatever the class is.
If it is a UIView for example, I would subclass it like so:
#class JVView : UIView <NSCopying>
I would then implement the copyWithZone: method appropriately, copying any of the properties of the instance that you feel are necessary.

Related

what is the use of - (id)init in NSObject

Today I was going through some of the online codes and I found some NSObject Class.
Some are having:
- (id)init
{
self = [super init];
return self;
}
And some doesn't have it.
Then I also tried this in my Sample Code. I was totally confused. Before this I was thinking that we must write -(id)init method to instantiate a NSObject Class. But now it is working without it.
Here are my some of my doubts:
is -(id)init method really necessary?
What happens if we don't use it.
If we don't write init method even then my code works. Why?
Having an empty -init has absolutely no function.
NSObject already has -init method. And methods in Objective-C are inherited.
It's the same as overriding any other method and just call super:
- (void)someMethod {
[super someMethod];
}
You'll find answers to your questions in the Apple documentation on initializers. I'd recommend you go through those materials, they will clarify a lot of things.
To sum up the documentation with regards to your questions:
is -(id)init method really necessary?
If you don't need to perform extra logic when your class is instanced, then you don't need to implement an init in your class.
What happens if we don't use it.
Even if you don't need to implement it in your subclasses, you need to call it when creating a new object, e.g. [[MyClass alloc] init]
If we don't write init method even then my code works. Why?
As I wrote above, you don't need to declare one for your class, but you need to call it. Otherwise your code might not properly work.
[super init] is highly recommended to give a chance for the superclass to also properly configure the newly created object.
Not calling super init is an error, and results are undefined. (Bad things my happen)
-init() is initializer of NSObject. If a user creates a Person Class which inherits NSObject. It can override this initializer, or one can create their own custom initializer as show below
eg.
class Person : NSObject
{
let name:String
//Initializer inherited from NSObject
override init()
{
super.init()
}
//Custom Initializer
init(withName name:String)
{
super.init()
self.name = name
}
}

Confusion when using the self keyword

I have a few questions about this code:
#import "ViewController.h"
#interface ViewController ()
#property (copy, nonatomic) NSArray *myArray;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myArray= #[#"one", #"two", #"three", #"four"];
}
I know the self keyword means that's method will be sent to the receiver of that message, and I know when and how to use it if i was creating a simple command utility code, but when learning about creating an iPhone app and using the storyboard every time I see the self keyword it confuses me, I don't know which object is the receiver
2nd question, I know that #[#"object", #"object"];is quick way to create an NSArray object, but "myArray" is a property not an NSArray object. please explain, thank you.
myArray is. The name of a property, as you say. By default, the compiler will create an instance variable called _myArray that's used by that property. In any case, because you've declared the property to be of type NSArray * (and not readonly) you can assign an array to it.
The self keyword is simply a pointer to the "current" object, some instance of the class that you're writing code for when you type "self". If you assign something to self.myArray, the class in which you make that assignment needs to have a myArray property. In your code example, self is a pointer to the particular instance of ViewController that just loaded its view. None of that changes when you're writing an iPhone apportion using a storyboard. self is always the object receiving the method in which self is used. (Note: when used in a class method, i.e. one that starts with +, the object receiving the method is the class itself, not an instance of the class. Don't worry about this if it sounds confusing -- it doesn't come up all that often.)
If you find an expression like self.myArray confusing, it may help to know that property syntax is just shorthand for a method call. Also, self in an expression like that isn't special at all. The syntax is foo.bar where foo can any object pointer (including self) and bar can be any property of the object pointed to by foo. The expression translates directly to either [foo bar] or [foo setBar:...], depending on whether you're reading or assigning a value to the property. So,
self.myArray = #[a, b, c];
means exactly the same as:
[self setMyArray:#[a, b, c]];
self always corresponds to the self class. So every instance of a class will have its own self.
In your case myArray is a property of Class ViewController. Here you can refer to the property by using self.myArray or _myArray.
In the following statement you are creating an array with four strings and adding it to myArray.
self.myArray= #[#"one", #"two", #"three", #"four"];
Your wordings in the question :
I know the self keyword means thats method will be sent to the
receiver of that message
is valid for a method call where you use it as :
[self aMethod];
Even in this you are calling a method which is a part of the class. If you call any method which is not of the current(self) class then you call it by using that class' object name as:
SomeClass *someClassObject = ...
[someClassObject itsMethod];
"self" is a pointer to object to which the method belongs. In your case you may have many instances of ViewController and each of them can call viewDidLoad and in that method "self" is the pointer to the instance itself. To look at it from the C perspective you could create a method using pointer to function where you would also send own pointer to the function called "self", for instance void foo(MyClass *self); to call it then myClassInstance->foo(myClassInstance); this procedure kind of simulates methods but you always need to send instance pointer as well (self). So there should be no confusion as to what "self" is except it is more commonly known by "this" keyword. It is just a reference to the object on which the method is being called.
The property is just a convenience of usually 2 methods called getter and setter. When creating a property #property NSArray *myArray you will actually generate a pointer usually NSArray *_myArray; then a getter:
- (NSArray *)myArray {
return _myArray;
}
And a setter
- (void)setMyArray:(NSArray *)myArray {
_myArray = myArray;
}
How getters and setters are created depends on property attributes (strong, weak, readonly...). You may even override any of these methods or both. So as you stated "but "myArray" is a property not an NSArray object" a property can have truly any type.

Create a class that inherits a list of objects in Objective-C

Coming from a .NET background, I used to make classes that looked a lot like this:
MyClass
Inherits List(Of SomeOtherClass)
I am getting smoked trying to do this in Objective-C. I am wanting to have a class that is a collection of UIImageViews.
I tried this, which is wrong (it inherits from NSArray):
- (id)init
{
//I know I'm not using an imageview here, this was just a proof of concept
self = [super initWithObjects:[UIImage imageNamed:#"btnSideMenu"], nil];
if (self) {
}
return self;
}
The collection is a fixed size, so it won't need to be mutable. However, if using a NSMutableArray provides more syntactical sugar than I would not be opposed to it.
I think a subclass for this is excessive. Subclasses should be used to add functionality to a super class. You should just make an NSMutableArray of UIImageViews

How do I get subclass to initialize property as its correct class?

I have a class named SPPanelManager, which has a property of another class, named SPPanelSettingsManager. SPPanelManager has the following in it's -init method:
self.settingsManager = [[SPPanelSettingsManager alloc] init];
The purpose of SPPanelManager is to be subclassed, and the subclasses are used throughout my app. For example, there's SPGreetingManager. In the .h file of SPGreetingManager, I have declared:
#property (nonatomic, strong) SPGreetingSettingsManager *settingsManager;
which makes the settingsManager be of the correct class. The problem is that when the SPGreetingManager subclass is initialized, it calls the init method above, and initializes the settingsManager as the SPPanelSettingsManager class, rather than SPGreetingSettingsManager.
How can I get it to initialize this as the correct class for that property without having to re-write the init code in every subclass?
The super class (SPPanelManager) somehow has to know which class the concrete panel manager wants to use as a settingsManager.
Apple uses the following approach to match CALayers to UIViews:
The base class declares a class method that returns the concrete SPPanelSettingsManager subclass:
// in SPPanelManager.h
+ (Class)settingsManagerClass;
... which subclasses override to return their custom class:
// in SPGreetingManager.m
+ (Class)settingsManagerClass
{
return [SPGreetingSettingsManager class];
}
Now the superclass can instantiate the settings manager as follows:
self.settingsManager = [[[[self class] settingsManagerClass] alloc] init];
Another common solution is to use a naming convention. Just match the names of the classes: SPGreetingManager has a SPGreetingSettingsManager.
By definition each ...Manager has to have a matching ...SettingsManager.
// in SPPanelManager.m init
NSString *className = NSStringFromClass([self class]);
className = [className stringByReplacingOccurrencesOfString:#"Manager"
withString:#"SettingsManager"];
Class settingsManagerClass = NSClassFromString(className);
NSAssert(settingsManagerClass != Nil, #"no settings manager class found");
self.settingsManager = [[[settingsManagerClass settingsManagerClass] alloc] init];
The advantage is that subclasses don't have to override a common method to declare the class type. On the other hand it might seem a bit obfuscated what's going on.
Also, above code forces a one to one relationship between the classes. No settings controller could be reused.
Is SPPanelManager a class you developed? Simply give it a init with a parameter for the settings instance.

Is it ok not to invoke [super init] in a custom init method?

I have a MKPolyline subblass which I want to implement NSCoding, i.e.
#interface RSRoutePolyline : MKPolyline <NSCoding>
I asked a question on the best way to encode the c-array and got an excellent answer. However, there is no init method defined on MKPolyline, i.e. there is no other way to give it data other than its class method polylineWithPoints:points.
Is this code where my comment is ok?
- (void)encodeWithCoder:(NSCoder *)aCoder
{
MKMapPoint *points = self.points;
NSUInteger pointCount = self.pointCount;
NSData *pointData = [NSData dataWithBytes:points length:pointCount * sizeof(MKMapPoint)];
[aCoder encodeObject:pointData forKey:#"points"];
[aCoder encodeInteger:pointCount forKey:#"pointCount"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
NSData* pointData = [aDecoder decodeObjectForKey:#"points"];
NSUInteger pointCount = [aDecoder decodeIntegerForKey:#"pointCount"];
// Edit here from #ughoavgfhw's comment
MKMapPoint* points = (MKMapPoint*)[pointData bytes];
// Is this line ok?
self = (RSRoutePolyline*)[MKPolyline polylineWithPoints:points count:pointCount];
return self;
}
You should call an init method on any subclass of NSObject. Since MKPolyline is an NSObject, you should init it.
But MKPolyline has no methods and no init. This is Objective C's was of telling you that you can't subclass it.
Instead, as WDUK suggested, define your own class. It keeps track of your list point points, and manages NSCoding to save and restore them as needed.
#interface RSPolyline: NSObject<NSCoding>
- (id) initWithPoints: (NSArray*) points;
- (id) initWithCoder:(NSCoder *)aDecoder;
- (void) encodeWithCoder:(NSCoder *)aCoder;
- (MKPolyline*) polyLine;
#end
Your class can generate a polyline on request, perhaps caching the result if performance is an issue.
As a rule, don't reach for inheritance first. When you want to extend and improve a class, think first of composition.
It's dirty not to call [super init], and it doesn't bode well with my idea of good programming. Without calling super yourself, it isn't a true subclass; just a bastardization of composition that relies on a side effect of calling a convenience constructor. Saying this, I believe your method described will work OK, but it goes against the grain of good Objective-C programming and its conventions.
What I would suggest is to use MKPolyLine as an MKPolyLine instance, and use a category to add the extra bells and whistles you need. As for adding extra instance variables and such, you can use associated objects. An introduction to this concept can be found here, and this SO question addresses the use of them with categories: How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?
While it is generally allowed to create and return a different object in an init method, there are three problems with that line (explained below). Instead of this, I would suggest overriding the points and pointCount properties so that you can return values stored in an instance variable, and call the super implementation there if the instance variable is empty. Then, your initializer just sets these instance variables so that they will be used.
- (MKMapPoint *)points {
if(myPointsIvar == NULL) return [super points];
else return myPointsIvar;
}
// similarly for pointCount
The first problem is that you are creating a new object, but not releasing the old one, which means you are leaking it. You should store the result in a different variable, then release self, then return the result (you don't need to store it in self).
Second, polylineWithPoints:count: returns an autoreleased object, but initWithCoder: should return a retained one. Unless there is another retain on it, it could be deallocated while you are still using it.
If these were the only problems, you could solve both like this:
MKPolyline *result = [MKPolyline polylineWithPoints:points count:pointCount];
[self release];
return [result retain];
However, there is a third problem which cannot be solved so easily. polylineWithPoints:count: does not return a RSRoutePolyline object, and the object it returns may not be compatible with your subclass's methods (e.g. it probably won't support NSCoding). There really isn't a way to fix this, so you can't use polylineWithPoints:count:.

Resources