How is known to support FE protocol, I must implement method:
– countByEnumeratingWithState:objects:count:
But it method is do not knows what type of object I want enumerate. For example my custom object has two arrays:
NSArray* names - for NSString objects;
NSArray* sites - for NSURL objects;
Now I want enumerate them:
for( NSString* name in myObj )
{
}
and
for( NSURL* url in myObj )
{
}
Can I do that – countByEnumeratingWithState:objects:count: define what kind of objects it must enumerate? (Without using additional class attributes :) )
No. Fast enumeration can only support one type of enumeration per class so you would have to decide which case is more important for you.
However, NSEnumerator also supports fast enumeration. So your class could support 2 different enumerators (let's call them nameEnumerator and urlEnumerator) and the class's users can then use fast enumeration like this:
for (NSString *name in [myObj nameEnumerator]) { ... }
for (NSURL *url in [myObj urlEnumerator]) { ... }
No, type information is not available in that way. I can't think of any mainstream language that would allow return type polymorphism in this way, which is what you're asking for.
Why not simply expose the arrays as properties?
#interface myObj {
NSArray *names;
NSArray *sites;
}
#property(readonly) NSArray *names;
#property(readonly) NSArray *sites;
#end
#implementation myObj
#synthesize names, sites;
#end
Then you can do this:
for (NSString* name in myObj.names) {
}
for (NSURL* sites in myObj.sites) {
}
Yes, you can do that as long as you ensure that only NSStrings are in names and only NSURLs in sites. You only make a cast with "NSString*" telling the compiler that you know that names contains NSString objects. You don't actually enforce that these are only NSString objects. Hope that helped.
for( NSString* name in [myObj names] ) {…}
and
for( NSURL* url in [myObj sites] ) {…}
Related
I don't have too much experience with iOS, but I am working on some legacy code. In the project, we use an object as the key of a dictionary:
NSMutableDictionary * dict;
RoleContainer * role = [Class getRole];
[dict setObject:[Class getData] forKey:role];
We have the role passed to another function. When we try to retrieve the data:
data = [dict objectForKey:role];
Sometimes the return value is empty. It happens about 10% of time. I stepped through the code and found out after passing role to the function the reference of the "role" object had been changed! For example, from 0x002bf500 to 0x00222bad.
Why?
In order to play nicely with NSMutableDictionary your RoleContainer class must implement a hash and isEqual methods. Otherwise, equal roles may get recorded twice in the dictionary, or querying by a valid key may fail.
Here is a brief sample of how you could implement your hash/isEqual when your class has an identifying member:
#interface RoleContainer : NSObject
#property (nonatomic, readonly) NSString *name;
- (NSUInteger)hash;
- (BOOL)isEqual:(id)anObject;
#end
#implementation RoleContainer
#synthesize name = _name;
- (NSUInteger)hash {
return [name hash];
}
- (BOOL)isEqual:(id)anObject {
if (![anObject isKindOfClass:[RoleContainer class]]) {
return NO;
}
RoleContainer *other = (RoleContainer*)anObject;
return [_name isEqual:[other name]];
}
#end
In that code, dict is going to be nil, so you're sending messages to nothing. Is it actually pointing to something later on?
I'm assuming your RoleContainer responds to the stringValue method, which might be a good place to look at what is going on if it's overloaded.
If it's using the standard string value, then it's returning the class and memory location. This may not be reliable if someone down the line is resetting objects to keys.
You may also have an issue where the getData object is being released somewhere where it shouldn't be touched. Try enabling NSZombieEnabled in the debugger, or enable ARC.
try
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
Also it would make sense to have a look at your Class. Is it a class, and getRole a class-method? is it an object?
I am currently facing the problem to check whether a property of an Object (NSManagedObject) exists or not.
Unfortunately the method
[[MyObject class] respondsToSelector:#selector(myProperty)];
always returns NO.
I think it's because the property generated by CoreData is a new style property ala
#property (nonatomic, strong) NSString *myProperty
So any ideas how to solve this issue?
I would really appreciate all of your suggestions ;)
Thanks in advance!
Alex
[[MyObject class] respondsToSelector:...] asks whether the metaobject responds to that selector. So, in effect, it asks whether there is a class method with that selector. Your code would return YES if you had:
+ (NSString *)myProperty;
It returns NO because you have the equivalent of the instance method:
- (NSString *)myProperty;
You need to call respondsToSelector: on an instance of your class.
You could normally use instancesRespondToSelector: directly on the metaclass (so, [MyObject instancesRespondToSelector:...]) but Core Data synthesises the relevant method implementations only when you create an object, so that's a non-starter. You could however create an instance via the normal NSEntityDescription route and test respondsToSelector: on that.
Since it's all Core Data, an alternative would be to ask the NSManagedObjectModel for the relevant NSEntityDescription via its entitiesByName dictionary and inspect the entity description's propertiesByName dictionary.
The only cases I've required this has been to set things dynamically so I am only looking for the setter. I am just composing the signature for the setter and then testing that it exists and then using it.
NSArray * keys = [myObject allKeys];
for(NSString * key in keys)
{
NSString * string = [NSString stringWithFormat:#"set%#:", [key capitalizedString]];
SEL selector = NSSelectorFromString(string);
if([myObject respondsToSelector:selector] == YES)
{
id object = [dict objectForKey:key];
// To massage the compiler's warnings avoid performSelector
IMP imp = [card methodForSelector:selector];
void (*method)(id, SEL, id) = (void *)imp;
method(myObject, selector, object);
}
}
This code satisfies a need where you may not be digesting all the data you receive in the dictionary.
In this case it was sparse json, so some data may not always exist in the json so stepping thru myObjects attributes looking for their corresponding key would just be a lot of wasted effort.
Are you synthesizing the property in the class file?
#interface SomeClass : NSObject
{
#property (nonatomic, strong) NSString *myProperty
}
#end
#implementation SomeClass
#synthesize myProperty;
#end
I'm not sure how to manage this, as objective-c is wierd enough for me
I'm have this derived class
#interface DoctorsSet : NSObject { NSString *tableid;
NSString *doctor_name;
NSString *doctor_surname;
NSString *city;
NSString *State;
NSString *phone; }
It has a custom constructor on which I'm initializing the properties as params...
THe problem is I have several functions that return this type, so how so I assign to a temporary local variable this type, or if my data comes from a NSMutableArray and I want to get that object at index ID
here are the 2 cases which I couldn't handle, because on assign it give an access error
NSMutableDictionary *doctors_set;
for(i=[doctors_sets count]-1;i>=0;i--) {
//this doesn't work
DoctorsSet * set=[doctors_set objectAtIndex:i];
}
i don't want to use for(DoctorsSet *set in doctors_sets)
because i want to pass the array in the reverse order....
If the end goal is to go in reverse use
for (DoctorsSet *set in [doctors_sets reverseObjectEnumerator])
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.
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;
}