This question already has an answer here:
Confusion with distinct and indistinct object
(1 answer)
Closed 7 years ago.
I'm trying to do a NSCountedSet but I need to ignore a property, I tried overriding the isEqual method of my object, and doing a manual compare of all the properties except the one I want to ignore but it doesn't work
Any idea on how to achieve it?
UPDATE
My class
#interface GSOrderMenuMenuContent : GSBaseModel
#property (copy, nonatomic) NSNumber *order_content_id;
#property (copy, nonatomic) NSNumber *item_id;
#property (copy, nonatomic) NSNumber *price;
#property (copy, nonatomic) NSNumber *priceWithModifiers;
#property (copy, nonatomic) NSString *course;
#property (copy, nonatomic) NSString *itemName;
#property (nonatomic) GSMenuItem* item;
#property (nonatomic) NSMutableArray *modifiers;
#property (copy, nonatomic) NSNumber *isAlreadyPrinted;
#property (copy,nonatomic) NSNumber *isDeleted;
-(GSOrderMenuMenuContent*)deepCopy;
-(GSOrderContent*) orderContent;
-(BOOL)isEqual:(GSOrderMenuMenuContent*)object;
#end
Usage:
NSCountedSet* countedSet = [[NSCountedSet alloc] initWithArray:contents];
Where contents is an array of class objects
Adding a breakpoint to the isEqual gets not called (however it is if doing a [NSarray containsObject:...]
As mentioned in the docs for the isEqual: method, you must always implement a corresponding hash method. Those two methods must always be implemented together.
Two objects that compare as equal must also return the same hash value.
Related
I have a dictionary containing data for user from a REST endpoint. Here is my user class
#import <Foundation/Foundation.h>
#interface User : NSObject
#property (strong, nonatomic) NSString *uid;
#property (strong, nonatomic) NSString *email;
#property (strong, nonatomic) NSString *firstName;
#property (strong, nonatomic) NSString *lastName;
#property (assign, nonatomic) int status;
#end
I have a method to set all properties
/*
* set properties
*/
- (void)setPropertiesWithDictionary:(NSDictionary *)dictionary{
for(NSString *key in dictionary){
object_setIvar(self,
class_getInstanceVariable([self class], [[#"_" stringByAppendingString:key] UTF8String]),
dictionary[key]);
}
}
Instead of doing something like
[user setUid:#dictionary[#"uid"]];
I want to call my method like this
[user setPropertiesWithDictionary: dictionary];
Just wondering if implementing object_setIvar this way is fine. If not - Would be really great if you can explain why. Thanks in advance.
Do whatever you like, but why reinvent the wheel when key value coding (KVC) already exists? Just call this method:
https://developer.apple.com/documentation/objectivec/nsobject/1417515-setvaluesforkeyswithdictionary?language=objc
KVC does what you're trying to do, but it does it a lot better than you're likely to do it.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html
I think your problem might occur with "int status", because dictionary[# "status"] is not of type int.
In your code implementation,user.status = dictionary[# "status"],this result is unpredictable.
Unless you make a type judgment, user.status = [dictionary[# "status"]intValue];
I recommend a third-party framework on github called MJExtension that fulfills your needs.You can look at the source code.
I have a multi view application and use an object to keep track of my logged in user. My User.h looks like this
#interface User : NSObject
#property (strong, nonatomic) NSDictionary *data;
#property (weak, nonatomic) NSString *uid;
#property (weak, nonatomic) NSString *firstName;
#property (weak, nonatomic) NSString *lastName;
#property (weak, nonatomic) NSString *dob;
#property (weak, nonatomic) NSString *gender;
#property (weak, nonatomic) NSString *avatarURL;
#property (assign, nonatomic) NSInteger status;
- (void)setPropertiesWith:(NSDictionary *)data;
And the User.m looks like this
#import "User.h"
#implementation User
/*
* set properties
*/
- (void)setPropertiesWith:(NSDictionary *)data{
self.data = data;
self.uid = self.data[#"uid"];
self.firstName = self.data[#"firstName"];
self.lastName = self.data[#"lastName"];
self.dob = self.data[#"dob"];
self.gender = self.data[#"gender"];
self.status = [[self.data valueForKeyPath:#"status"] intValue];
self.avatarURL = self.data[#"avatarURL"];
}
#end
I had the data as weak, but in one of the views it would turn up null - I believe ARC was releasing it. Please correct me if I am wrong.
I have 2 questions:
With this setup, the data being strong and the rest of the properties being weak, is there any potential risk to this?
Should I make the data an ivar and keep the rest as is?
There is no actual reason(other than my poor class design skills) for the existence of the properties. I just find it very interesting and wanted to understand what is going on.
You asked:
With this setup, the data being strong and the rest of the properties being weak, is there any potential risk to this?
Yes, if you nil the dictionary, all of your properties would likely become nil, assuming you don’t have other strong references to them elsewhere.
Should I make the data an ivar and keep the rest as is?
I wouldn’t even make it an ivar (unless there’s some other requirement for saving this that you haven’t shared with us). It should just be a local variable, and make your properties copy (or strong).
I’d suggest (a) getting rid of the NSDictionary property and (b) making the NSString properties be copy (or strong), not weak. Also, rather than having a setPropertiesWith method, I’d just define an initializer:
// User.h
#interface User : NSObject
#property (copy, nonatomic) NSString *uid;
#property (copy, nonatomic) NSString *firstName;
#property (copy, nonatomic) NSString *lastName;
#property (copy, nonatomic) NSString *dob;
#property (copy, nonatomic) NSString *gender;
#property (copy, nonatomic) NSString *avatarURL;
#property (assign, nonatomic) NSInteger status;
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
#end
And
// User.m
#implementation User
- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
if ((self = [super init])) {
self.uid = dictionary[#"uid"];
self.firstName = dictionary[#"firstName"];
self.lastName = dictionary[#"lastName"];
self.dob = dictionary[#"dob"];
self.gender = dictionary[#"gender"];
self.status = [dictionary[#"status"] intValue];
self.avatarURL = dictionary[#"avatarURL"];
}
return self;
}
#end
And then, the caller would do:
User *user = [[User alloc] initWithDictionary:someDictionary];
There are other refinements you could consider here (e.g. readonly public interface, declaring nullability, lightweight generics on the dictionary, etc.), but the above is probably a good starting point.
By the way, if your wondering why I made these copy instead of strong, we just want to protect ourselves in case the caller passed a NSMutableString (which is a NSString subclass) and accidentally mutated it later. This is just a bit safer, a little more defensive pattern.
I'm creating an app that will create a form which a user will then fill out and save for later use.
#interface DataModel : NSObject
#property (strong, nonatomic) NSString *whiskeyName;
#property (strong, nonatomic) NSNumber *whiskeyRating;
#property (strong, nonatomic) NSString *whiskeyColor;
#property (strong, nonatomic) NSString *whiskeyNose;
#property (strong, nonatomic) NSString *whiskeyFlavors;
#property (strong, nonatomic) NSString *whiskeyFinish;
#property (strong, nonatomic) NSString *whiskeyNotes;
The app will store multiple copies of these forms (think of Apple's Notes app). I've created a class composed of NSStrings and NSNumbers but I'm having a difficult time figuring out a way save them to an NSArray to access later. I've just started fooling around with Core Data but everything I've found will only save a single form. How can I save multiple versions of a class in an array to be opened and edited for later use? Sorry if the question is vague, but I've been hitting my head on a wall and am having a hard time finding a working solution.
If I understand correctly you have sub-classed NSObject and want to save multiple instances of this class into an array? If that is the case, then a MutableArray should be able to hold any object:
// .m file
#import "DataModel.h"
#interface YourViewController
#property (strong, nonatomic) NSMutableArray *myArray;
#end
#implementation YourViewController
- (void) viewDidLoad {
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:numberOfObjectsToStore];
DataModel *myClassInstance1 = [[DataModel alloc] init];
myClassInstance1.whiskeyName= #"somevalue";
myClassInstance1.whiskeyRating= 5;
DataModel *myClassInstance2 = [[DataModel alloc] init];
myClassInstance2.whiskeyName= #"someothervalue";
myClassInstance2.whiskeyRating= 2;
[myArray addObject:myClassInstance1];
[myArray addObject:myClassInstance2];
}
I have a custom NSObject called MAAssignment. It's basically a data type that has a number of #properties and one custom init method:
#property (nonatomic, strong) NSDate *date;
#property (nonatomic, strong) NSString *assignmentName;
#property (nonatomic, strong) NSNumber *totalPoints;
#property (nonatomic, strong) NSNumber *recievedPoints;
#property (nonatomic, strong) NSNumber *classAverage;
#property (nonatomic, strong) NSNumber *extraCredit;
#property (nonatomic, strong) NSNumber *notGraded;
- (id)initWithDate:(NSString *)date assignmentName:(NSString *)assignmentName totalPoints:(NSNumber *)totalPoints recievedPoints:(NSNumber *)recievedPoints classAverage:(NSString *)classAverage extraCredit:(NSNumber *)extraCredit notGraded:(NSNumber *)notGraded;
I create an instance of it in the viewController, hoping to populate the newly created item with some data... But I can't figure out how to access the variables of the object. I went MAAssignment *assignment = [[MAAssignment alloc] init];, then I tried [assignment setDate] or assignment.date = ddate but none of them seem to work.
Am I misunderstanding how the accessors for objects work?
You should place these variables in h. file
of MAAsignment
I'm not understanding your question very well (where are you declaring this code? What's the full code of your MAAsiignment initialization example?), however I'll try to answer anyway.
Are you sure that the #property declarations are inside the #interface in .h and not inside .m?
The #interface inside .m is a private class extensions, and allows you to declare private properties. To make them available outside, you need to put them inside the header (.h).
Please post more code to let us provide a more exhaustive answer.
What you describe is a data container object. It should work as described:
MAAssignment *anAssignment = [[MAAssignment alloc] init];
anAssignment.date = [NSDate date];
anAssignment.totalPoints = #(10);
NSLog(#"anAssignment.date = %#", anAssignment.date);
NSLog(#"anAssignment.totalPoints = %#", anAssignment.totalPoints);
Should work perfectly. Are you getting any warnings?
I'm trying to make a deep copy of an NSMutableArray whose objects are instances of a custom class similar to this:
#interface CustomParent : NSObject
#property NSInteger Id;
#property (strong, nonatomic) NSString *IdStr;
#property (weak, nonatomic) NSDate *Date;
#property (strong, nonatomic) NSMutableArray *CustomChildren;
#property (strong, nonatomic) CustomType *Type;
#property float Value;
#end
I know there are lots of posts dealing with copying objects, but I don´t find examples for getting a complete copy of objects with collection members or properties. NSMutableArray *dstArray = [[NSMutableArray alloc] initWithArray:srcArray copyItems:YES]; raises an exception involving the copyWithZone method.
How can I do this? Thanks!
In order to deep copy the content of the array
[[NSMutableArray alloc] initWithArray:srcArray copyItems:YES];
will send copyWithZone: to every object inside the collection. If they don't respond to this selector, you'll get a crash.
Have your CustomParent class to conform to the NSCopying protocol and you're done.
Here's some extra info on how do achieve it: Implementing NSCopying