Ok, so I have the code below (Objective-C FYI) and I was wondering if I want to create an NSMutableArray of c_data objects, how would I go about doing that? It's sort of like declaring a List<c_data> cData in C#.
#interface c_data : NSObject {
double value;
int label;
int ID;
}
#property double value;
#property int label;
#property int ID;
-(c_data*) init;
-(c_data*) initWithValue:(double)value;
#end
#implementation c_data
#synthesize value, label, ID;
-(c_data*) init {
return self;
}
-(c_data*) initWithValue:(double)val {
value = val;
return self;
}
#end
If you look at the class feat_data, I'm trying to make cData an array of the class c_data. I have included my attempts at it, but I don't think it's right because c_data isn't an array. Any suggestions?
#interface feat_data : NSObject {
NSMutableArray *nData;
NSMutableArray *cData;
char type;
}
#property(nonatomic, retain) NSMutableArray *nData;
#property(nonatomic, retain) NSMutableArray *cData;
#property char type;
-(feat_data*)init;
#end
#implementation feat_data
#synthesize nData, cData, type;
-(feat_data*)init {
nData = [[NSMutableArray alloc] init];
c_data *c_dataInstance = [[c_data alloc] init];
cData = [[NSMutableArray alloc] initWithArray:c_dataInstance];
return self;
}
#end
There is no such thing as statically typed / template / generic collections in Objective-C. Basically, the point of a strongly-typed collection is to provide static type safety at compile time. Such an approach makes little sense in a language as dynamic as Objective-C. The approach to the problem of disparate object types in Objective-C collections is to only insert the appropriate object type(s). (Also, remember that the array will retain objects it contains, so if you insert a new object without releasing and you lose the pointer to it, you're leaking memory.)
If you think about it, one of the biggest benefits to generics is being able to retrieve objects from the collection directly into a statically-typed variable without casting. In Objective-C, you can just store to an id variable and send whatever message you like without fretting about a ClassCastException, or the compiler complaining that an object doesn't (may not?) implement the method you're attempting to invoke. You can still statically type variables and cast results if desired, but the easier approach is to use dynamic typing (and -isKindOfClass: and -respondsToSelector: if necessary).
Incidentally, there are several related incarnations of this question on Stack Overflow. Knowing the term(s) to search for ("generic", "strongly-typed", or "template") can help find them. Here are a few:
Why do C# and VB have Generics? What benefit do they provide?
Is there any way to enforce typing on NSArray, NSMutableArray, etc.?
Is there anything like a generic list in Cocoa / Objective-C?
Are there strongly typed collections in Objective-C?
Finally, I agree with William — your init methods are pretty egregious in the sample you provided. You'd do well to learn and heed Apple's rules of Allocating and Initializing Objects in Objective-C. It requires breaking habits from other languages, but it will save you endless hours of insanity at some point down the road. :-)
[NSMutableArray addObject:[[[c_data alloc] init] autorelease]];
Objective-C arrays aren't typed. It seems you have some C++ unlearning to do.
On a related note, your inits are pretty bad. You need to call super init as well, as such:
- (id)init {
self = [super init];
if (self != nil) {
//Initialize here.
}
return self;
}
You would create an NSMutableArray and insert c_data objects into it.
Related
I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.
I have a situation where it seems like I need to add instance variables to a category, but I know from Apple's docs that I can't do that. So I'm wondering what the best alternative or workaround is.
What I want to do is add a category that adds functionality to UIViewControllers. I would find it useful in all my different UIViewControllers, no matter what specific UIViewController subclass they extend, so I think a category is the best solution. To implement this functionality, I need several different methods, and I need to track data in between them, so that's what led me to wanting to create instance methods.
In case it's helpful, here's what I specifically want to do. I want to make it easier to track when the software keyboard hides and shows, so that I can resize content in my view. I've found that the only way to do it reliably is to put code in four different UIViewController methods, and track extra data in instance variables. So those methods and instance variables are what I'd like to put into a category, so I don't have to copy-paste them each time I need to handle the software keyboard. (If there's a simpler solution for this exact problem, that's fine too--but I would still like to know the answer to category instance variables for future reference!)
Yes you can do this, but since you're asking, I have to ask: Are you absolutely sure that you need to? (If you say "yes", then go back, figure out what you want to do, and see if there's a different way to do it)
However, if you really want to inject storage into a class you don't control, use an associative reference.
Recently, I needed to do this (add state to a Category). #Dave DeLong has the correct perspective on this. In researching the best approach, I found a great blog post by Tom Harrington. I like #JeremyP's idea of using #property declarations on the Category, but not his particular implementation (not a fan of the global singleton or holding global references). Associative References are the way to go.
Here's code to add (what appear to be) ivars to your Category. I've blogged about this in detail here.
In File.h, the caller only sees the clean, high-level abstraction:
#interface UIViewController (MyCategory)
#property (retain,nonatomic) NSUInteger someObject;
#end
In File.m, we can implement the #property (NOTE: These cannot be #synthesize'd):
#implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
We also need to declare and define the class MyCategoryIVars. For ease of understanding, I've explained this out of proper compilation order. The #interface needs to be placed before the Category #implementation.
#interface MyCategoryIVars : NSObject
#property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
#end
#implementation MyCategoryIVars
#synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
#end
The above code declares and implements the class which holds our ivars (someObject). As we cannot really extend UIViewController, this will have to do.
I believe it is now possible to add synthesized properties to a category and the instance variables are automagically created, but I've never tried it so I'm not sure if it will work.
A more hacky solution:
Create a singleton NSDictionary which will have the UIViewController as the key (or rather its address wrapped as an NSValue) and the value of your property as its value.
Create getter and setter for the property that actually goes to the dictionary to get/set the property.
#interface UIViewController(MyProperty)
#property (nonatomic, retain) id myProperty;
#property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary;
#end
#implementation UIViewController(MyProperty)
-(NSMutableDictionary*) propertyDictionary
{
static NSMutableDictionary* theDictionary = nil;
if (theDictionary == nil)
{
theDictioanry = [[NSMutableDictionary alloc] init];
}
return theDictionary;
}
-(id) myProperty
{
NSValue* key = [NSValue valueWithPointer: self];
return [[self propertyDictionary] objectForKey: key];
}
-(void) setMyProperty: (id) newValue
{
NSValue* key = [NSValue valueWithPointer: self];
[[self propertyDictionary] setObject: newValue forKey: key];
}
#end
Two potential problems with the above approach:
there's no way to remove keys of view controllers that have been deallocated. As long as you are only tracking a handful, that shouldn't be a problem. Or you could add a method to delete a key from the dictionary once you know you are done with it.
I'm not 100% certain that the isEqual: method of NSValue compares content (i.e. the wrapped pointer) to determine equality or if it just compares self to see if the comparison object is the exact same NSValue. If the latter, you'll have to use NSNumber instead of NSValue for the keys (NSNumber numberWithUnsignedLong: will do the trick on both 32 bit and 64 bit platforms).
This is best achieved using the built-in ObjC feature Associated Objects (aka Associated References), in the example below just change to your category and replace associatedObject with your variable name.
NSObject+AssociatedObject.h
#interface NSObject (AssociatedObject)
#property (nonatomic, strong) id associatedObject;
#end
NSObject+AssociatedObject.m
#import <objc/runtime.h>
#implementation NSObject (AssociatedObject)
#dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, #selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, #selector(associatedObject));
}
See here for the full tutorial:
http://nshipster.com/associated-objects/
It mentioned in many document's online that you can't create create new variable in category but I found a very simple way to achieve that. Here is the way that let declare new variable in category.
In Your .h file
#interface UIButton (Default)
#property(nonatomic) UIColor *borderColor;
#end
In your .m file
#import <objc/runtime.h>
static char borderColorKey;
#implementation UIButton (Default)
- (UIColor *)borderColor
{
return objc_getAssociatedObject(self, &borderColorKey);
}
- (void)setBorderColor:(UIColor *)borderColor
{
objc_setAssociatedObject(self, &borderColorKey,
borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.layer.borderColor=borderColor.CGColor;
}
#end
That's it now you have the new variable.
Why not simply create a subclass of UIViewController, add the functionality to that, then use that class (or a subclass thereof) instead?
Depending on what you're doing, you may want to use Static Category Methods.
So, I assume you've got this kind of problem:
ScrollView has a couple of textedits in them. User types on text edit, you want to scroll the scroll view so the text edit is visible above the keyboard.
+ (void) staticScrollView: (ScrollView*)sv scrollsTo:(id)someView
{
// scroll view to someviews's position or some such.
}
returning from this wouldn't necessarily require the view to move back, and so it doesn't need to store anything.
But that's all I can thinkof without code examples, sorry.
I believe it is possible to add variables to a class using the Obj-C runtime.
I found this discussion also.
Totally new to Obj-C, so thanks for patience. :P
Because I'm beginner, I will use the car example. Easier for me to understand.
I have an object, Car. It has two member objects, tire and engine.
Tire and engine have their own member variables too, but they are just int with various names (like pressure, treadDepth).
In all these cases, I have synthesized accessor methods. I'm not sure about accessor methods for objects, so I just did #property id engine / #property id tire. Hope that is right!
Now, I can do dot.notation style to access like: [car.engine cylinders]. Fine! Sending tire and engine messages works fine. I write methods, this notation seems to work.
But when I declare an array of objects like 4 tires for the car:
#interface Car : NSObject {
tire *tires[4];
}
I cannot send it message like this
[car.tire[0] setPressure: int];
It says accessing unknown tires getter method.
Basically I am wondering if someone can help me understand how to correctly access member variables of an object that is in an array.
Thanks!
You are trying to call a getter on car that doesn't exist. You can't return a C-style array by value anyway, so instead of just returning a Tire* pointer i'd rather use a NSArray in this case:
// header:
#interface Car : NSObject {
NSArray *tires;
}
#property (nonatomic, copy) tires;
// ...
// source:
#implementation Car
#synthesize tires;
- (id)init {
if ((self = [super init])) {
tires = [[NSArray alloc] initWithObjects:
[[[Tire alloc] init] autorelease],
// ...
nil];
// ...
}
return self;
}
- (void)dealloc {
[tires release]; // don't forget to clean up
// ...
}
Now you could use the getter:
[[[car.tires] objectAtIndex:0] setPressure:0];
Why not put all of your tire objects into an NSArray or NSSet? Or, since you know there are only four, you could simply define frontLeftTire, frontRightTire, etc. properties.
Well you could use Objective-C style arrays. Then you would have something like:
NSArray *tires = [NSArray arrayWithObjects: tire1, tire2, tire3, tire4];
And then you would access them as:
[tires objectAtIndex:0];
That's assuming you are using the synthesized methods as described. I'm not sure from your question, but it seems like you might want to define a class "tire" for these objects (rather than just a method, which is all I see above) that inherits from NSObject, or maybe from your own class CarPart, etc. Then you allocate 4 tires in a loop and call an init method that sets up some default state (hopefully better than the donut that came as the spare in my car) and then add them to your array in "Car" when you initialize a car.
Does anyone know of a way to add additional attribute types to the #property keyword without modifying the compiler? Or can anyone think of another way to genericize getter/setter creation?
Basically, I have a lot of cases in a recent project where it's handy for objects to lazily instantiate their array properties. This is because we have "event" objects that can have a wide variety of collections as properties. Subclassing for particular events is undesirable because many properties are shared, and it would become a usability nightmare.
For example, if I had an object with an array of songs, I'd write a getter like the following:
- (NSMutableArray *)songs {
if (!songs) {
songs = [[NSMutableArray alloc] init];
}
return songs;
}
Rather than writing dozens of these getters, it would be really nice to get the behavior via...
#property (nonatomic, retain, lazyGetter) NSMutableArray *songs;
Maybe some fancy tricks via #defines or something? Other ideas?
You can always use macros. Even if you modified the compiler, you would probably still want to do this in #synthesize instead of #property, since there is no need to publish this implementation detail. And with a macro it is easy to use any init method. Unfortunately the macros are not aware of the getter= property attribute.
#define synthesizeLazyGetterWithInit(PROPERTY,TYPE,INIT)\
-(TYPE *) PROPERTY { if ( !PROPERTY ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }
#define synthesizeLazyGetter(PROPERTY,TYPE)\
synthesizeLazyGetterWithInit(PROPERTY,TYPE,init)
#implementation MyClass
synthesizeLazyGetter(songs,NSMutableArray)
synthesizeLazyGetterWithInit(other,NSMutableArray,initWithCapacity:0)
#end
Edit:
#define synthesizeLazyGetterOptional(PROPERTY,TYPE,INIT);\
-(TYPE *) PROPERTY:(BOOL)inAllocate { if ( !PROPERTY && inAllocate ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }\
-(TYPE *) PROPERTY { return [self PROPERTY:YES]; }\
-(BOOL) PROPERTY##Initialized { return nil != PROPERTY; }
I'm using C structs in objc and I've created a function that assembles the structure like the one from the Cocoa API. The things is that this structure is not like NSRect o NSPoint this structure packs objc objects soo I'm seeing a potential memory leak here. Do I need to provide a function to 'release' the structure?
I'am not creating a ISKNewsCategory class because there will be no behavior but Do you think this is a good approach or I should define the class even doe there will be no behavior?
typedef struct ISK_NewsCategory {
NSString *name;
NSString *code
} ISKNewsCategory;
NS_INLINE ISKNewsCategory ISKMakeNewsCategory(NSString *name, NSString *code) {
ISKNewsCategory category;
category.name = [name retain];
category.code = [code retain];
return category;
}
In general you would be much better off creating a simple container class. That way all the memory management is easy and you are able to use the object in the standard Cocoa container classes without mucking around wrapping the struct in an NSValue or whatever.
The only time it might be acceptable to use a struct in this way is if you have extremely performance-critical code where the object overhead might become a problem.
#interface ISKNewsCategory : NSObject
{
NSString *name;
NSString *code;
}
#property (copy) NSString *name;
#property (copy) NSString *code;
#end
#implementation ISKNewsCategory
#synthesize name,code;
- (void)dealloc
{
self.name = nil;
self.code = nil;
[super dealloc];
}
#end
As of 2018 you can now use ObjC pointers in C structs and they are retained while the struct is in memory. https://devstreaming-cdn.apple.com/videos/wwdc/2018/409t8zw7rumablsh/409/409_whats_new_in_llvm.pdf
Anything you retain you must release. However, there is nothing that says you must retain them. If the structure is "owning" the objects, then yes, you should retain them, and then you must release them. If the objects are retained elsewhere, though, you might want to consider weak references where you don't retain the objects.
I hate to create classes with no behavior too. :/ This is a sad aspect of Objective-C: classes are verbose.
You have to remember that structures in C are copied each time they're passed around. Therefore, if your structures retain their objects and you give them to someone else, you automatically end up with an erroneous reference count for the objects in it.
If you plan on passing around your objects at all, I think you should make it a full-fledged class. If you don't, a simple struct will be okay.
As of the need of a "destructor", you should have one. You should always have one if there is cleanup to do for your structure.
I hope this solution will be helpful for you.
typedef struct ISK_NewsCategory {
NSString *name;
NSString *code;
} ISKNewsCategory;
NS_INLINE ISKNewsCategory ISKMakeNewsCategory(NSString *inName, NSString *inCode) {
ISKNewsCategory category;
[category.name autorelease];
category.name = [inName retain];
[category.code autorelease];
category.code = [inCode retain];
return category;
}