How to use methods from NSManagedObject entity using NSManagedObject - iphone

I am using a NSManagedObject to save some values, but not using entity for that. Because I want to not limit it to some entities. I tried using (Oist *)managedObject.entity, not working. How to use this managedObject to get theIt's like this:
Oist.h
#class File;
#interface Oist : NSManagedObject
#property (nonatomic, retain) NSSet *files;
#end
#interface Oist (CoreDataGeneratedAccessors)
- (void)addFilesObject:(File *)value;
File.h
#class Oist;
#interface File : NSManagedObject
#property (nonatomic, retain) Oist *gist;
#end
- (void)newManagedObjectWithClassName:(NSString *)className forRecords:(NSDictionary *)records
{
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:className inManagedObjectContext:[[GPCoreDataController sharedInstance] backgroundManagedObjectContext]];
[records enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[self setValue:obj forKey:key forManagedObject:newManagedObject];
}];
}
- (void)setValue:(id)value forKey:(NSString *)key forManagedObject:(NSManagedObject *)managedObject
{
File *fileEntity = [NSEntityDescription insertNewObjectForEntityForName:#"File" inManagedObjectContext:[[GPCoreDataController sharedInstance] backgroundManagedObjectContext]];
if ([key isEqualToString:#"files"])
{
NSDictionary *files = (NSDictionary *)value;
for (NSString *key in [files allKeys]) {
NSDictionary *file = [files valueForKey:key];
NSLog(#"%#", file[#"filename"]);
[fileEntity setValue:file[#"filename"] forKey:#"filename"];
[fileEntity setValue:file[#"type"] forKey:#"type"];
}
} else if ([key isEqualToString:#"id"])
{
if ([managedObject.entity.name isKindOfClass:[Oist class]]) {
//here I want to use Oist's method - (void)addFilesObject:(File *)value; how to do that?
}
[managedObject setValue:[NSNumber numberWithInt:[value integerValue]] forKey:#"gistID"];
}
}

I may be misunderstanding your question, but it looks like you're hoping to cast a generically typed (NSManagedObject *) as a more specifically typed subclass.
The way to check if the pointer passed generically is in fact an instance of your subclass is this:
if ([managedObject isKindOfClass:[Oist self]]) {
// managedObject may safely be cast to an Oist*
}
You can do the cast without an assignment, like this:
[(Oist *)managedObject addFiles...];
Or, with proper parentheses, access a property (the dot operator has higher precedence than the cast, so you need to tell the compiler you want the cast first):
((Oist *)managedObject).entity
But I think that's less clear to the reader and potentially more keystrokes than an explicit assignment with a cast, which is what I'd recommend:
if ([managedObject isKindOfClass:[Oist self]]) {
Oist *oist = (Oist *)managedObject;
[oist addFilesObject:someFilesObject];
}

Related

Subclass NSString

I want to add a property to a NSString object. For this reason I want to subclass it.
I try to make something like this:
#interface MyString : NSString
#property (nonatomic) NSInteger userId;
#end
so then I can do
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
testString.userId = 2;
NSLog(#"testString: %#", testString); //-> Want it to return "testString: hello"
NSLog(#"userId: %d", testString.userId); //-> Want it to return "userId: 2"
I don't know how to subclass NSString (create storage facilities, override some methods (length, characterAtIndex). Have an idea?
Don't try to subclass NSString to do this. Create an entirely new class that is a subclass of NSObject and give it 2 properties (and a set of methods to access the properties if you want to).
Trying to use NSString is overly complicated and not appropriate.
For this line:
NSLog(#"testString: %#", testString);
all you need to do is implement the description method on your custom class to return the string property. Then the string will be printed when you use NSLog.
Subclassing class cluster classes is tricky, as you've discovered. Which is why, generally, it is pretty much never done.
Instead, create a class that encapsulates two strings; the string that would point to #"hello" in your example and the userId.
#interface MyThingy:NSObject
#property(copy) NSString *stringData;
#property(copy) NSString *userId;
#end
... etc ...
This will be far more flexible and it will be easier to refactor in the future.
BTW, this doesn't make sense:
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
Under manual retain/release, it is a leak. Under ARC, it is a purposeless allocation.
Why don't you use NSMutablestring in this you can use appendString method in which you can add your any stringValue and then just pass the same to your string.
Try this category. You can add any kind of custom object to anything coming from NSObject - basically any class - by use of a key. Retrieve the object using that key. I think I got this from someone (found it) here on stackoverflow.
Header:
//
// NSObject+arbitraryobjectonanynsobjectlol.h
//
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import <Foundation/Foundation.h>
// https://stackoverflow.com/a/10319083/129202
#interface NSObject (arbitraryobjectonanynsobjectlol)
- (id)associativeObjectForKey: (NSString *)key;
- (void)setAssociativeObject: (id)object forKey: (NSString *)key;
#end
And the implementation:
//
// NSObject+arbitraryobjectonanynsobjectlol.m
// someone
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import "NSObject+arbitraryobjectonanynsobjectlol.h"
#import <objc/runtime.h>
#implementation NSObject (arbitraryobjectonanynsobjectlol)
static char associativeObjectsKey;
- (id)associativeObjectForKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
return [dict objectForKey: key];
}
- (void)setAssociativeObject: (id)object forKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
objc_setAssociatedObject(self, &associativeObjectsKey, dict, OBJC_ASSOCIATION_RETAIN);
} [dict setObject: object forKey: key];
}
#end

Obj-C: How to improve repetitive method implementations using method forwarding

I have an implementation which contains a set of methods which do pretty much the same:
- (NSString *) specialKey{
[self.mySpecialDictionary valueForKey:#"specialKey"];
}
- (NSString *) anotherKey{
[self.mySpecialDictionary valueForKey:#"mySpecialKey1"];
}
I can now conveniently use those getters like so:
NSString *foo = [Setting sharedInstance].specialKey;
I guess I should now be able to define my Properties dynamic and make one implementation for all those cases, since the string which I look up in my dictionary will always be the name of the getter. I am pretty sure that this should be do-able in Objective-C, but I have no Idea how to achieve this.
The answer is in your question. Try method forwarding:
- (NSMethodSignature*) methodSignatureForSelector:(SEL)selector
{
return [mySpecialDictionary methodSignatureForSelector:#selector(valueForKey:)];
}
- (void) forwardInvocation:(NSInvocation *)invocation
{
NSString* propertyName = NSStringFromSelector(invocation.selector);
[invocation setSelector:#selector(valueForKey:)];
[invocation setArgument:&propertyName atIndex:2];
[invocation invokeWithTarget:mySpecialDictionary];
}
Of course, to get rid of compiler warnings it needs to define every property explicit
#property (nonatomic, readonly) NSString* specialKey;
#property (nonatomic, readonly) NSString* anotherKey;
and provide #dynamic for them.
What about this?
- (NSString *)valueForKey:(NSString *)key
{
return [self.mySpecialDictionary valueForKey:key];
}
this will return the value for the provided key. Or this for more flexible use
- (NSString *)valueForKey:(id)key
{
if([key isKindOfClass:[NSString class]]){
return [self.mySpecialDictionary valueForKey:key];
}
}
Or even this
- (id)valueForKey:(id)key
{
if([key isKindOfClass:[NSString class]]){
return [self.mySpecialDictionary valueForKey:key];
} else if (..){
// catch more possible keys here ...
}
}

Read plist stored in memory to NSDictionary

According to this post I can use the encryption/decryption methods to store/retrieve plist file securely.
But the problem is:
Q: After I have decrypted the plist file, how can I parse and store the plist file as NSDictrionary object
Probably NSPropertyListSerialization is what you are looking for.
As seen in this Post:
Plist Array to NSDictionary
You could use core foundation approach here with the method CFPropertyListCreateFromXMLData
If the plist represents the NSDictionary content, the following check should be passed:
if ([(id)plist isKindOfClass:[NSDictionary class]])
and the plist object might be safely casted to NSDictionary. If no, something is wrong with the data or decription process.
The easiest way would be creating a category for NSDictionary like this:
NSDictionaryWithData.h:
#interface NSDictionary (NSDictionaryWithData)
+ (id)dictionaryWithData:(NSData *)data;
- (id)initWithData:(NSData *)data;
#end
NSDictionaryWithData.m:
#implementation NSDictionary (NSDictionaryWithData)
+ (id)dictionaryWithData:(NSData *)data
{
return [[[NSDictionary alloc] initWithData:data] autorelease];
}
- (id)initWithData:(NSData *)data
{
self = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NULL
errorDescription:nil];
return [self retain];
}
#end
Usage:
NSDictionary* myDict = [[NSDictionary alloc] initWithData:decryptedData];
One of the possible reasons dictionaryWithData doesn't exist is a property list is not necessarily a dictionary at the root level. It could equally be an NSArray.
Here is my take on a solution: a category that utilises NSPropertyListSerialization
Features
Silently discards data that contains arrays at the root level.
Checks which method to use ( propertyListFromData:mutabilityOption:format:errorDescription: is depreciated )
NSMutableDictionary also supported
Note - this takes an unorthodox approach of wrapping a class factory method with an init method. This is for efficiency - most of the time you will be using the factory method, which just wraps NSPropertyListSerialization, which internally invokes alloc/init/autorelease to return an appropriate object.
NSDictionary+DictionaryWithData.h
#import <Foundation/Foundation.h>
#interface NSDictionary (DictionaryWithData)
+ (id)dictionaryWithData:(NSData *)data;
- (id)initWithData:(NSData *)data;
#end
NSDictionary+DictionaryWithData.m
#import "NSDictionary+DictionaryWithData.h"
#implementation NSDictionary (DictionaryWithData)
+(NSPropertyListMutabilityOptions) mutabilityOption {
return NSPropertyListImmutable;
}
+ (id)dictionaryWithData:(NSData *)data
{
static BOOL methodChecked = NO;
static BOOL use_propertyListWithData = NO;
if (!methodChecked) {
SEL sel = #selector(propertyListWithData:options:format:error:);
use_propertyListWithData = [[NSPropertyListSerialization class]
respondsToSelector:sel];
methodChecked = YES;
}
id result;
if (use_propertyListWithData) {
result = [NSPropertyListSerialization propertyListWithData:data
options:[self mutabilityOption]
format:nil
error:nil];
} else {
result = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:[self mutabilityOption]
format:NULL
errorDescription:nil];
}
return [result isKindOfClass:[NSDictionary class]] ? result : nil;
}
- (id)initWithData:(NSData *)data
{
id result = [[self class] dictionaryWithData:data];
self = result ? [self initWithDictionary:result ] : nil;
return self;
}
#end
#implementation NSMutableDictionary (DictionaryWithData)
+(NSPropertyListMutabilityOptions) mutabilityOption {
return NSPropertyListMutableContainersAndLeaves;
}
#end

How to serialize a class in IOS sdk (Objective-c)?

How to serialize the following class in objective-c so that it can be used with SBJson?
I get "JSON serialisation not supported for Animal" error when I use this code.
Can someone point out where I am going wrong?
The contents of Animal.h file is as below
#import <UIKit/UIKit.h>
#interface Animal : NSObject<NSCoding> {
NSString *name;
NSString *description;
NSString *imageURL;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSString *imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u;
#end
The contents of Animal.m file is as below
#import "Animal.h"
#implementation Animal
#synthesize name, description, imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u {
self.name = n;
self.description = d;
self.imageURL = u;
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if(self = [super initWithCoder:aDecoder])
{
name = [[aDecoder decodeObjectForKey:#"name"] retain];
description = [[aDecoder decodeObjectForKey:#"description"] retain];
imageURL = [[aDecoder decodeObjectForKey:#"imageURL"] retain];
}
return [self initWithName:name description:description url:imageURL];
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[super encodeWithCoder:encoder];
[encoder encodeObject:name forKey:#"name"];
[encoder encodeObject:description forKey:#"description"];
[encoder encodeObject:imageURL forKey:#"imageURL"];
}
#end
Make your custom class conform to NSCoding protocol and then serialize it.
For more info, visit the Apple documentation
Also, this link will also help you.
As suggested in this link, archive your custom class to NSData and serialize that as provided in the Apple documentation.
Edit
Make your Animal.m as follows:
#import "Animal.h"
#implementation Animal
#synthesize name, description, imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u {
self = [super init];
if( self )
{
self.name = n;
self.description = d;
self.imageURL = u;
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if( self )
{
self.name = [aDecoder decodeObjectForKey:#"name"];
self.description = [aDecoder decodeObjectForKey:#"description"];
self.imageURL = [aDecoder decodeObjectForKey:#"imageURL"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:name forKey:#"name"];
[encoder encodeObject:description forKey:#"description"];
[encoder encodeObject:imageURL forKey:#"imageURL"];
}
#end
To actually answer your question on how to do it using SBJson: Implement the proxyForJson method. Unless you are serializing an NSArray or NSDictionary you must override this method for serialization to work.
You can see that this is the case by looking at the SBJson source code (in SBJsonWriter.m):
- (NSData*)dataWithObject:(id)object {
...
if ([object isKindOfClass:[NSDictionary class]])
ok = [streamWriter writeObject:object];
else if ([object isKindOfClass:[NSArray class]])
ok = [streamWriter writeArray:object];
else if ([object respondsToSelector:#selector(proxyForJson)])
return [self dataWithObject:[object proxyForJson]];
else {
self.error = #"Not valid type for JSON";
return nil;
}
...
}
}
Implement proxyForJson in Animal.m like this (not tested):
- (NSDictionary*) proxyForJson
{
return [NSDictionary dictionaryWithObjectsAndKeys:self.name, #"name",
self.description, #"description",
self.imageURL, #"imageURL",
nil];
}
This open source project JSONCoding makes the whole process pretty simple, using the new sdk class in conjunction with the NSCoding protocol.
Check the newly introduced NSJSONSerialization class:
NSJSONSerialization class
I think you can check out this if it helps you: Make a Custom Class Serializable
Please check this Property List Programming Guide - Serializing a Property List
and the similar post here:
Make a Custom Class Serializable in Objective-c/iPhone?
Object serialization in XML format using Obj-C / iPhone SDK
See also https://github.com/jsonmodel/jsonmodel
Magical Data Modeling Framework for JSON - allows rapid creation of
smart data models. You can use it in your iOS, macOS, watchOS and tvOS
apps.
This is also the chosen library for the Objective-c Swagger client.

#dynamic properties and its usage?

Can anyone give me clear picture about dynamic property and its usage? y not use the usual #property everywhere?
Dynamic properties are used when you don't provide an implementation at compile time, but ensure that one exists at runtime. Being a dynamic language, Objective-C can respond to messages at runtime, even if the class doesn't have an implementation at compile time.
Here's a contrived example: Let's say you have a Book class, backed by an NSMutableDictionary that contains the keys title and author. However, you want Book to respond to title and author as well, and have them as properties; title and author will grab the appropriate value from the dictionary, and setTitle: and setAuthor: will change the value stored in the dictionary. You could do so with this code:
#import <Foundation/Foundation.h>
#interface Book : NSObject
{
NSMutableDictionary *data;
}
#property (retain) NSString *title;
#property (retain) NSString *author;
#end
#implementation Book
#dynamic title, author;
- (id)init
{
if ((self = [super init])) {
data = [[NSMutableDictionary alloc] init];
[data setObject:#"Tom Sawyer" forKey:#"title"];
[data setObject:#"Mark Twain" forKey:#"author"];
}
return self;
}
- (void)dealloc
{
[data release];
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
NSString *sel = NSStringFromSelector(selector);
if ([sel rangeOfString:#"set"].location == 0) {
return [NSMethodSignature signatureWithObjCTypes:"v#:#"];
} else {
return [NSMethodSignature signatureWithObjCTypes:"##:"];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString *key = NSStringFromSelector([invocation selector]);
if ([key rangeOfString:#"set"].location == 0) {
key = [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];
NSString *obj;
[invocation getArgument:&obj atIndex:2];
[data setObject:obj forKey:key];
} else {
NSString *obj = [data objectForKey:key];
[invocation setReturnValue:&obj];
}
}
#end
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Book *book = [[Book alloc] init];
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
book.title = #"1984";
book.author = #"George Orwell";
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
[book release];
[pool release];
return 0;
}
Note the the methods are "created" at runtime via forwardInvocation:; hence, title and author are dynamic properties.
(This isn't the best example, but I think it gets the point across.)
#dynamic thing; is merely a way to inform the system not to generate getters/setters for the thing, that you (or someone else) will provide them for you—As in, they'll be there at runtime.
This is in contrast to #synthesize which tells the compiler to generate the getter/setter (as appropriate) for you.
#dynamic is (in my experience) used primarily in conjunction with Core Data and subclasses of NSManagedObject. To quote Marcus Zarra's Core Data,
By declaring them
[attributes/relationships], we are
telling the compiler to ignore any
warnings associated with there
properties because we "promise" to
generate them at runtime. Naturally,
if the turn up missing at runtime,
then our application is going to
crash.