I would like to create an NSObject class that I can use the instance of and save to its variables and later pass its data elsewhere (NSManagedObject). Do I need to do anything else besides creating a new Object-C Class that inherits from NSObject. Create Variables in .h and synthesize in .m.
i.e.:
my .h file:
#import <Foundation/Foundation.h>
#interface MyDataClass : NSObject
#property (nonatomic, retain) NSNumber *variable1
#property (nonatomic, retain) NSString *variable2
#property (nonatomic, retain) NSDate *variable3
#end
.m file:
#import "MyDataClass.h"
#implementation MyDataClass
#synthesize variable1, variable2, variable3
#end
I would like to be able do the following in some SomeViewController:
#property (nonatomic, strong) MyDataClass *newDataClass
#systhesize newDataClass;
newDataClass.variable1 = #"123457890";
newDataClass.variable2 = #"This is the new Variable";
newDataClass.variable3 = [NSDate date];
Is there anything else I need to do to initialize each variable when an instance of this class is created? Am I missing anything?
That's all that you need for a custom object which you want to use to store data.
Of course when you go to use it (in SomeViewController), you need to actually create an instance of your class before you start setting the variables:
self.newDataClass = [[MyDataClass alloc] init];
I would also use self.newDataClass instead of just newDataClass unless you have a reason not to.
Related
i successfully integrated core data in my JSQ project, for my JSQMessageData i use NSManagedObject i created called CDChatMessage
#interface CDChatMessage : NSManagedObject < JSQMessageData >
#end
at my JSQMessagesViewController i use NSfetchedresultsController,
it works fine for text messages but i can't figure out how to implement media messages.
JSQMessage.h have a property that represent the Media Data
#property (copy, nonatomic, readonly) id< JSQMessageMediaData > media;
but obviously i cant assassin property of type JSQMessageMediaData to my NSManagedObject,
anyone have a solution for using JSQMessageMediaData with Core Data ?
thanks.
Basically what I've done to solve this kind of issue is this:
Instead of using CoreData object which conforms to JSQMessageData I use something called viewModel.
A ViewModel is basically a normal NSObject which just unwraps all necessary information from the CoreData object and conforms to JSQMessageData protocol - providing text, senderId, and other information (and also media message if necessary)
#interface ChatMessageViewModel : NSObject <JSQMessageData>
#property (nonatomic, strong, readonly) CDChatMessage *chatMessage;
// main properties
#property (nonatomic, copy, readonly) NSString *text;
#property (nonatomic, copy, readonly) NSString *senderId;
#property (nonatomic, copy, readonly) NSString *watcherId;
...
#property (nonatomic, strong, readonly) JSQMessage *mediaMessage;
- (instancetype)initWithChatMessage:(CDChatMessage *)chatMessage;
#end
.m file could look like this:
#interface ChatMessageViewModel ()
#property (nonatomic, strong, readwrite) CDChatMessage *chatMessage;
// main properties
#property (nonatomic, copy, readwrite) NSString *text;
#property (nonatomic, copy, readwrite) NSString *senderId;
#property (nonatomic, copy, readwrite) NSString *watcherId;
...
#property (nonatomic, strong, readwrite) JSQMessage *mediaMessage;
#end
#implementation ChatMessageViewModel
- (instancetype)initWithChatMessage:(CDChatMessage *)chatMessage
if (self = [super init]) {
_chatMessage = chatMessage;
[self unpackViewModel];
}
return self;
}
- (void)unpackViewModel {
self.senderId = self.chatMessage.senderId;
self.text = self.chatMessage.senderId;
self.mediaMessage = [self unpackMediaData];
}
- (JSQMessage *)unpackMediaData {
// Here CDCustomPhotoMediaItem is a subclass of JSQPhotoMediaItem which just lets me create custom look of JSQ media item.
JSQPhotoMediaItem *photoItem = [[CDCustomPhotoMediaItem alloc] init];
return [JSQMessage messageWithSenderId:self.senderId displayName:#"" media:photoItem];
}
After I fetch data using NSFetchResultsController I just take all core data objects and turn them into immutable viewModels.
Then in cellForItemAtIndexPath I just call this:
cell.mediaView = [viewModel.media mediaView];
This approach creates nice immutable wrapper which contains only necessary chunk of information needed by the JSQ chat library. Also, you can easily write tests for such object. If you're using swift, you can use struct for this kind of purpose.
Hope my answer helps. Please ask if you need more detailed answer. ;-)
I'm new to objective-C, so apologies if this is repeated somewhere. I have a category(?) that is something like:
inside SomeClass.h:
#interface SomeClass (SomeCategory) <SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#property (nonatomic, retain) id someProperty; // <-- i want to move this to "private"
#end
and now in my SomeClass.m, all i have is:
#implementation SomeClass (SomeCategory)
// dynamic setters/getters here for someProperty.
#end
I think the someProperty is public. how do i make this "private"? (in other words, how do i syntactically put this in the .m file? i tried to use
#interface SomeClass (SomeCategory) {
#property (nonatomic, retain) somePrivateProperty;
}
#end
but it just complains that i have duplicate definition of the category. how do i do this correctly?
In your .h file, you should not give the category. Just use:
#interface SomeClass : SomeBaseClass < SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#end
In your .m file, define your private property inside a class extension:
#interface SomeClass ()
#property (nonatomic, retain) id somePrivateProperty;
#end
A class extension is not a like category in that it allows you to extend an interface as well as add new storage to your class.
In a class category, you can define new properties, but no storage will be allocated for it, so you have to do it by hand:
#interface SomeClass (SomeBaseCategory)
#property (nonatomic, retain) id somePrivateProperty;
#end
#implementation SomeClass {
id _somePrivateProperty;
}
- (void)setSomePrivateProperty:(id)property {
_somePrivateProperty = property;
}
- (id)somePrivateProperty {
return _somePrivateProperty;
}
#end
Otherwise your app will crash.
In any case, keep in mind that given the dynamic nature of Objective-C, your property will never be fully private, since you can always send a message to an Objective-C object through objc_msgsend and thus set or read the property value.
EDIT:
If you do not have the source code for a class implementation, you cannot define a class extension (as per source linked above).
In this case, you could use object association to define properties.
Just add the category definition in the .m file OUTSIDE the implementation block
Like so:
#interface MyClass (MyCategory)
#property (assign) BOOL myPrivateProperty;
#end
#implementation MyClass
...
#end
Categories are best used for adding capability to code you do not own and cannot change. Adding properties via categories is not impossible, but is much more difficult.
Class Extensions are best used for keeping properties your object needs, but are not intended to be public.
If you do truly need to add properties to this object, the way to do it is with the Objective-C runtime's associated objects
There's an excellent writeup of when/how to use them here
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 have a CoreData-based app. In Core Data, I have an entity called ZSProduction which creates an NSManagedObject subclass called ZSProductionCD. This is the .h file created.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface ZSProductionCD : NSManagedObject
#property (nonatomic, retain) NSNumber * appVersion;
#property (nonatomic, retain) id highlightColour;
#property (nonatomic, retain) NSDate * lastUpdated;
#property (nonatomic, retain) NSString * notes;
#property (nonatomic, retain) NSString * owner;
#property (nonatomic, retain) NSString * productionID;
#property (nonatomic, retain) NSString * productionName;
#property (nonatomic, retain) NSNumber * scenesLocked;
#property (nonatomic, retain) NSNumber * shotNumberingStyle;
#property (nonatomic, retain) NSNumber * sortIndex;
#property (nonatomic, retain) NSNumber * status;
#property (nonatomic, retain) NSString * tagline;
#end
I then subclass this with a class called ZSProduction:
#import <Foundation/Foundation.h>
#import "ZSProductionCD.h"
#interface ZSProduction : ZSProductionCD
#end
The reason for subclassing is that I am likely to add a bunch of methods & possibly other properties. This way, if I make changes to the entity, I can write out a new ZSProductionCD class without affecting what I've done with ZSProduction.
Now here's the problem. I'm using ZSProduction in a view controller. But I'm having a problem with just one of the properties.
In this view controller, I declare a property:
#import "ZSProduction.h"
#interface [...]
#property (strong, nonatomic) ZSProduction *item;
#end
And then later, in a method:
self.productionNameField.text = self.item.productionName;
self.shotNumStyleControl.selectedSegmentIndex = [self.item.shotNumberingStyle intValue];
And that's where it goes wrong. XCode complains:
Property 'shotNumberingStyle' not found on object of type 'ZSProduction *'
Note that it doesn't complain about the productionName property, which works fine.
In the same view controller, if I use:
self.item.shotNumberingStyle = 0;
Then I get the same error. But if I use:
[self.item setValue:0 forKey:#"shotNumberingStyle"];
Then it works fine. Yet I can use:
self.item.highlightColour = [UIColor whiteColor];
with no problem at all. What gives?
Any clues would be appreciated.
Well, I sorted the problem, but I thought I'd leave this here in case someone else has something similar.
I realised that the three properties that were being inherited okay, and were accessible, wee ones I'd created in an earlier version of the ZSProduction class - one that didn't use Core Data (I'm currently refactoring to move from archives to CD).
It turned out that there were old ZSProduction.h and ZSProduction.m files on the disk, in the project subdir - but not in XCode. Seems that XCode was looking at these. The old files were in the root dir for the project, while the newer files were in a subdir (called 'Model'). I deleted the old files, restarted XCode & all is now tickety-boo.
I have a UITableViewController :
#import <UIKit/UIKit.h>
#import "MainClass.h"
#interface MainViewController : UITableViewController
#property (strong, nonatomic) MainClass *mainClass;
#end
And a class that i want to use as a data source for the table view:
#interface Domain : NSObject <UITableViewDataSource>
-(id) initWithName: (NSString*)name;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, retain) NSMutableArray* list;
#end
When i want to simply test if it's working i create a local domain and i add some documents in it:
Domain* domain = [[Domain alloc] init];
Document* document1 = [[Document alloc]initWithName:#"test1"];
[domain.list addObject:document1];
And then i declare the domain as a data source ( i overrides the two required methods) :
self.tableView.dataSource = domain;
Unfortunately, this cause a Bad access exception.
I guess it's because the local variables are released too soon.
I'm guessing this because when i declare both domain and document as property, it works just fine.
Can anyone explain me the reason of this too soon release and how to avoid it?
'dataSource' is a weak property, so you must keep another reference to the object for it not to be released.
Therefore defining a property on the view controller is really the best solution.
Create strong reference to domain, for example:
#property (strong, nonatomic) Domain* domain;
And change allocation of your domain object to:
self.domain = [[Domain alloc] init];
Document* document1 = [[Document alloc]initWithName:#"test1"];
[self.domain.list addObject:document1];
and after that:
self.tableView.dataSource = self.domain;