Passing array from one class to another using delegation - Best design pattern? - objective-c

The Problem
I have a class which calculates the path a user took using CoreLocation and and array of arrays containing the coordinates of each point (taken when the users location changes). This class method is being called by my View Controller, but I want to set it's delegate to another class which will store the result in Core Data or upload it to a database. I can return the array to the View Controller by using:
PathFinder.delegate = self
Then make my View Controller implement my delegate protocol, but this isn't what I want.
What I've Considered
I've thought about making the class which uploads the data to the database/stores it in Core Data a singleton class so that I can easily access it from my View Controller. E.g.
PathFinder.delegate = <MY SINGLETON CLASS>
Conclusion
What would be the best way to do this? Would it be bad practice to put the code to upload the array to my server in the PathFinder class? Any help would be appreciated.

I have something like this - a singleton class that manages a Core Data repository for images (some in the repository, some on the file system but a URL in the entity).
Why not have a singleton class that all objects that need the services import? That way, you tell some object to do something, when that works is done they tell the repository to save it. You can use a delegate protocol to know if it succeeded or not, but just decouple the saving of it from driving the process and knowing the outcome.

Related

Controller and JsonResult asp.net core

Why do i need to inherit from Controller to return JsonResult?
What is the mechanism that makes the JsonResult type available?
I've tried thinking on it and I figure maybe Controller declares it as a type, but I don't know.
You will need to inherit from Controller in order to use the Controller.Json utility method. You will however not need to inherit from Controller just to create a JsonResult. You can always just new-up one. As long as you are within a controller (not necessarily one that inherits Controller), this will still work:
return new JsonResult(object);
As for why you will need to inherit from Controller and not just ControllerBase; many of the result utility methods actually live in Controller. The reason for this is that those are targeted to view-centric controllers while ControllerBase is typically used for API controllers.
Now one would think that returning JSON results would be especially useful for API controllers but that is actually not the case: For API controllers, you should rather return an ObjectResult and have the conventions take care of serializing that into the format that was requested by the client. That way, an API controller can easily support formats like JSON and XML at the same time.

CoreData Model Objects for API

I am using CoreData in my application. I want to abstract out all the CoreData related stuff as an API so that the consume can use the API instead of directly using CoreData and its generated model objects. CoreData generates the managed objects model as following
#interface Person : NSManagedObject
#end
I want to define my API for example MyAPI and it has a function called as
createPerson:(Person*)p;
So the consumer of this createPerson API needs to create a Person data object (like POJO in java world) and invoke this API. But I cannot create Person object using
Person *p = [Person alloc] init]
because the designated initializer for this Person model created by CoreData does not allow this type of creation.
So should I define corresponding user facing data object may be PersonDO and this API should take that instead to carry the data into the API implementation?
Is my approach right? Any expert advise if design the API this way is a good design pattern?
You can't use CoreData without dealing with Managed Object Context. You MUST get the person from the context and save it in the context. If you don't want your customer to deal with that, and you don't use different threads in your app,you could create a api,that will call your appdelegate's Managed Object Context, and all the user will need to do is just to call that method.
For example,you could use automaticly generated by Core Data methods to make your API like that:
+ (Person *)newPersonWithAttributes:(NSDictionary *)userInfo {
// Call the designated initializer, but customer
// doesn't need to think about managed object context
return [Person initPesonWithAttributes:userInfo
inManagedObjectContext:[[AppDelegate sharedAppDelegate] managedObjectContext]];
}
You need lots of stuff to abstract that out. RestKit provides mechanisms to do that. Lighter weight would be InnerBand (See tutorial InnerBand CoreData) - though it does not automatically determine threads/queues for multi-threads.
However, it is a very simple API, and should give you most of what you want.

How should I import object instances into Core data?

I created a custom LocationGenerator class that uses CoreLocation and Reverse Geocoding, and generates (when asked) a custom Location object. My custom Location object has two instance variables - Address and GPS...both point to instance of two custom classes - Address is a bunch of strings and GPS is three floats - latitude, longitude and altitude.
Location = Address + GPS
For this to work, I needed to create three custom classes - Location, Address and GPS, all with default values set in their respective init methods.
Then I moved to Core Data. In the model I have these entities - Item, Location, Address and GPS. Item entity has some simple string properties and a Location relationship.
The location entity has a Address and GPS relatioship.
Since I moved to Core data, I deleted the custom classes Location Address and GPS I mention above and let Xcode generate classes from based on core data model.
The problem is, I am not sure how to create a Location instance in LocationGenerator anymore.
My former class definitions for Location and Address and GPS are gone, and in those from core data I should not override the init method.but should those generatede classess be a blueprint for my new Location object?
I guess my question is, how should I generate a location object in the LocationGenerator.
Should the LocationGenerator have its Location object created "inside" the managed object context?
To clarify from the UI point of view -I am just in the process of creating an Item, but it is not created yet, it waits for the Location..and only then is it inserted into core data..
Should I look at all objects that are created in the context the same way as i looked at objects before, with the only difference that they are in the context (and managed by the CD rules) and they persist?
The designated initializer for managed objects (Core Data objects, that is) is -initWithEntity:insertIntoManagedObjectContext: which is to say that you can't create a managed object without it being associated with a managedObjectContext. You indicate that you want to create the object, and then at some time later, decide whether or not to store it. There are essentially two ways to do that. The first way is to have some other object type that's not an NSManagedObject, but which you can use to populate an NSManagedObject subclass later when you decide to it should be persisted. The other way is to just created the managed object in the context, and then delete it from the context if it turns out that you don't need it.
NSManagedObjectContexts can be thought of as "scratch pads." Nothing is actually persisted until you -save: the context, so if you're going to be able to make a determination of whether or not to persist the object in the same workflow in which you're going to save the context, the second way is probably the way to go. If the lifetime of this pre-persisted data is longer than the standard workflow you're doing with your ManagedObjectContexts then the first way might be better.
HTH.

Using Login View Controller with ASIHttpRequest and Storyboard

OK, I am building an application that will be using ASIHttpRequest in several places to either get JSON data from a web service or will be posting to a web service. I have it working, but really don't like having several instantiations of the request object sprinkled around the different view controllers (Login view controller, a tableview controller, and a detail view controller. I would like to move all my ASIHttpRequest methods to one class and just get back a dictionary of values that came back from the web service. The problem with this is that the delegate methods don't return that I need to have returned.
What would be some suggestions on how I can consolidate all the methods that will create an HTTPRequest and return values when the request is finished.
I can post code if need be, but this is really more of a general question and not a specific issue. If there are any tutorials on how this should be done, I would appreciate it. I want my code to be efficient and pretty :)
Thanks!
Your problem is going to be asynchronousity. I'm not sure what you mean by consolidate, but you can have a singleton (you can just use your app delegate) to call the requests. So you would do something like this:
[(MyAppDelegateClass *)[UIApplication sharedApplication].delegate doLoginStuff:(NSDictionary *)params delegate:self];
If you're doing all this asynchronously, you can't just call this method and have it return something. You'll be stuck with having some sort of callback to your view controller, which is the way ASI works out of the box essentially. At best, you can minimize the code to generate the request and set any repetitive properties.
I'm not sure what you mean by having the instantiations floating throughout. If it's memory you're worried about, it would be no different reusing the same object. ASI typically uses an autoreleased request, so it would be the same as creating it in a "consolidated" method. If it's just clean code, I would do a singleton way and maybe make a shortcut c-based method call in some type of Utilities class that you create and import in with your prefix file. But again, you need the callback methods in your view controller so it doesn't get too much cleaner than it already is meant to work. I share your pain though.
When any request comes back, I almost always have a method that parses the results. Typically I'm only working with one type of web service, so have a method that parses the results and (also logs it to NSLog for debugging purposes) also gives me back an NSDictionary or NSArray.

Core Data returns NSManagedObject instead of Concrete class, but only when using . accessor

I have set up a Core Data model where I have two objects, say Person and Address. A person has an address, and an address can belong to many people. I have modelled it in core data as such (so the double arrow points to Person, while the single arrow goes to Address)
I have then created two classes for those objects, and implemented some custom methods in those classes. In the Core Data model I have entered the names of the classes into them.
If I fetch an Address from Core Data directly, it gives me the actual concrete class and I can call my custom methods on it.
If on the other hand I fetch a Person and try to access the Address through Person (eg: person.address) I get back an NSManagedObject that is an address (eg: I can get to all the core data attributes I've set on it) but it doesn't respond to my custom methods, because it's of type NSManagedObject instead of Address. Is this a limitation of Core Data or am I doing something wrong? If it is a limitation are there any work arounds?
Did you create those classes using the modeller (Select an Entity, File > new file.., Managed Object Class, then select the Model Entity)?
A while ago I had a similar problem because I didn't create my managed object models using the Modeller. What I did to make sure everything was up and running was to copy and save my custom methods (and everything else I'd implemented) and start from scratch using the modeller. Then I was able to customize my model classes again and everything worked just fine.
I know this is not a complete answer but perhaps it can help you until someone explains exactly what is going on.
Cheers!
You probably just forgot to set the name of the class in the model when you created the entity - it defaults to NSManagedObject. Click on Person and Address in the modeller and check, on the far right side where the Entity properties are listed, that the Class field is filled in correctly with the name of the corresponding objective C class and isn't just the default NSManagedObject setting.
Your implementation file for the class probably hasn't been added to the Target that you are running.
(Get Info on the .m file -> Check the targets tab)
If your xcdatamodel has the Class set, if it can't find it at run time it will still work, you will just get NSManagedObject instances back instead. Which will actually work just fine, until you try to add another method to the class, as you have found.