MKAnnotation - adding url - iphone

I'm working through mayurbirari's sample code to generate a mapkit view, I want to add a url to the popup. I've tried to understand the apple reference to subclass but TBH it just isnt going it.
I need to create a subclass that can have additional variable added to it as MKANNOTATION is core file and cannot be changed - therefore how do I do it?? I'm confused about how to set it up.
the code can be found here --> http://mayurbirari.wordpress.com/2011/02/07/how-to-access-mkmapkit-in-iphone/
if someone could show me the example of the subclass with URL added to it, it would probably sink in, but all the examples I've found seem to be over complicated.

MKAnnotation is a protocol that you have to adopt in your own class -- whichever class you're using to represent an annotation object. This is often a class that's part of your data model. For example, you might have a Person class and want to show instances of Person on a map. You'd adopt MKAnnotation in Person. It's easy to use properties for this:
#interface Person : NSObject <MKAnnotation>
{
//...
}
//...
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#end
And then implement the methods from MKAnnotation in your class:
#implementation Person
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
//...various methods of Person...
#end
Now you can add instances of Person to the map as annotations.

Related

Can I use a custom initializer for a core data model object?

I use Core Data and have an object ExerciseForRoutine. I'm currently manually creating it and then settings it's attributes, which seems to waste code. Is there any way I can create a custom init method to handle this in one line (I know how to do around alloc/init, but core data has a different init method..)
Current Code:
ExerciseForRoutine *exerciseForRoutine = (ExerciseForRoutine *)[NSEntityDescription insertNewObjectForEntityForName:#"ExerciseForRoutine" inManagedObjectContext:managedObjectContext];
exerciseForRoutine.name = self.selectedExercise;
exerciseForRoutine.timeStamp = date;
exerciseForRoutine.muscleGroup = self.muscleName;
exerciseForRoutine.musclePicture = self.muscleURL;
ExerciseForRoutine Class
#class Routine;
#interface ExerciseForRoutine : NSManagedObject {
#private
}
#property (nonatomic, strong) NSDate * timeStamp;
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSString * muscleGroup;
#property (nonatomic, strong) NSString * musclePicture;
#property (nonatomic, strong) Routine * exerciseToRoutine;
#end
#implementation ExerciseForRoutine
#dynamic timeStamp;
#dynamic name;
#dynamic muscleGroup;
#dynamic musclePicture;
#dynamic exerciseToRoutine;
I did this using awakeFromInsert and awakeFromFetch.
From Apple's documentation:
In a typical Cocoa class, you usually override the designated initializer (often the init method). In a subclass of NSManagedObject, there are three different ways you can customize initialization —by overriding initWithEntity:insertIntoManagedObjectContext:, awakeFromInsert, or awakeFromFetch. You should not override init. You are discouraged from overriding initWithEntity:insertIntoManagedObjectContext: as state changes made in this method may not be properly integrated with undo and redo.
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdManagedObjects.html
The classes which Xcode creates for handling core data objects should not be overridden, instead what you could do is create your own custom class which inherits from NSObject and write your methods to handle the managed object their.
Sol: You can do this with the help of the parameterized init method
Then it would look something like this
CoreDataHelperClass *someobj = [[CoreDataHelperClass alloc]initWithname:#"name" andTimeStamp:#"Time" andMuscleGroup:#"musclegroup" andPicture:UIImagePNGRepresentation(someimageObj)];
To do the above you need to add your own init method in the CoreDataHelperClass class like this
.h part of CoreDataHelperClass
- (id)initWithName:(NSString*)name andTimeStamp:(NSString*)timeStamp andMuscleGroup:(NSString*)group andPicture:(NSData*)imageData;
.m part of CoreDataHelperClass
- (id)initWithName:(NSString*)name andTimeStamp:(NSString*)timeStamp andMuscleGroup:(NSString*)group andPicture:(NSData*)imageData
{
//you assignment code to the core data attributes goes here
ExerciseForRoutine *obj = [[ExerciseForRoutine alloc]init];
obj.name = name;
obj.timestamp = timeStamp;
//and so on
return self;
}
Anyways what you could also do is pass a dictionary with the keyvalue pair get the values in your custom class or you may also pass an NSMutableArray like what ever suits your business model both will work.
You can get the values of Dictionary or Array inside your CoreDataHelperClass and assign those values to your attribute.
Hope i have got your query right if not then kindly mention the error part via comments
To add to #Radix's answer, you should consider using mogenerator because it'll do much of that subclassing business for you.
http://rentzsch.github.io/mogenerator/
See here for a guide to set it up and have it running on XCode 5.
There's a small caveat to watch out for though: if you get an assertion failure that reads:
-[MOGeneratorApp setModel:] blah blah blah
Then you should point mogenerator to the .xcdatamodel file inside of the .xcdatamodeld package in your Run Script Phase, like so:
mogenerator -m Model.xcdatamodeld/Model.xcdatamodel -O Project/Model --template-var arc=true
Where Project is the name of your project and Model is the name of your model.
See https://github.com/rentzsch/mogenerator/issues/169.

Forward declaring a protocol in objective-c

My class .h looks like:
#protocol AppInfoDelegate;
#class InfoTextView;
#interface AppInfoViewController : UIViewController <AppInfoDelegate> {
}
#property (nonatomic, retain) NSArray *textObjectsArray;
#property (nonatomic, retain) InfoTextView *itView;
#property (nonatomic, retain) UIButton *pgBackButton;
#property (nonatomic, retain) UIButton *pgFwdButton;
#end
#protocol AppInfoDelegate <NSObject>
- (void)closeButtonPressed:(id)sender;
#end
I get a warning that the protocol definition for AppInfoDelegate cannot be found. What is the proper way to do this and why cannot it not be found? Do I need to have the whole definition of the protocol before the interface? Thanks!
Using #protocol MyProtocol; is useful when you are asserting, for example, that a method will take id <MyProtocol> as an argument.
It is not useful when you are claiming that your class conforms to <MyProtocol>. The reason for this is that the compiler needs the full protocol declaration in order to verify that your class actually conforms to the protocol. (This compile-time check is one great reason to use formal protocols instead of the older informal ones.)
You can fix in two ways. One, as #skram suggests, is to just forward-declare the whole thing. This works, but it's also rather limited in my view. Why bother with a protocol in that case - just put everything in the class #interface and be done with it.
The second approach, which I prefer, is to actually have a separate header, such as MyProtocol.h. You can then freely import this into any header or implementation files as needed. This allows you to reuse a protocol easily (and avoid the headaches of circular imports that sometimes arise).
Try this:
#protocol AppInfoDelegate <NSObject>
- (void)closeButtonPressed:(id)sender;
#end
#class InfoTextView;
#interface AppInfoViewController : UIViewController <AppInfoDelegate> {
}
#property (nonatomic, retain) NSArray *textObjectsArray;
#property (nonatomic, retain) InfoTextView *itView;
#property (nonatomic, retain) UIButton *pgBackButton;
#property (nonatomic, retain) UIButton *pgFwdButton;
#end
Yes, superclass and adopted protocol definitions need to be defined (verbatim or by using #import) before the class definition. They cannot be forward-declared.
I've always seen the whole protocol definition before the #interface. I believe you can also put it into a separate file though

When declaring class properties/variables, can you just declare it via #property?

I've noticed that some generated classes only declare class properties/variables via #property, and don't include them within the #interface, as such:
#interface AddItemViewController : UITableViewController {
}
#property (nonatomic, retain) UITextField *itemName;
I was just curious if that's an acceptable way to do it, or if that is done for different reasons?
I normally do this:
#interface AddItemViewController : UITableViewController {
UITextField *itemName;
}
#property (nonatomic, retain) UITextField *itemName;
I declare it first in the #interface and then add the #property for it...
* Update *
I just wanted to update this a bit, because it's still not 100% clear to me.
I always thought that to declare a #property, you first needed to declare it within the #interface first, and then I saw this:
#interface mInventoryAppDelegate : NSObject <UIApplicationDelegate> {
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
All of those #property declarations are declared only as #properties, and not within the #interface.
For example, if I had say NSString *myString - I can declare that in the #interface and not as a #property and still have access to it no problem, but the getters and setters won't be created. I could also declare it in both. But what if I just declare it as #property, as such:
#interface AddItemViewController : UITableViewController {
}
#property (nonatomic, retain) NSString *myString;
Notice how I didn't add it between the #interface { } - how does it differ.
Sorry for repeating, but I'm just trying to reword this so that I can get an answer that makes more sense to me.
With the "modern" runtime, which the iPhone uses, the compilers can create the instance variable for you. Just use:
#synthesize itemName;
or if you prefer...
#synthesize itemName=_itemName;
...in your implementation. The compilers will then create ivar 'itemName' or '_itemName'.
This is of course for the case that the property is a simple getter/setter for one particular instance variable.
EDIT: NVM, per #bbum, what I thought of in my mind as the "32-bit" sim is actually the older simulator that didn't behave like the new runtime. The newer simulator is still 32-bit, and supports this behavior. See his comment below.
update
In response to your updated question:
The "interface" for a class is everything up to the #end. I think what you are calling "interface" is actually just the instance variables within the {}. What is between the {} are the instance variables for your class. The whole #interface includes those instance variables PLUS the method and #property declarations between the {} and the #end.
So I think what you are really asking is if you have a #property in your #interface, and that #property is just a simple getter/setter pair, then do you need to declare a "backing" instance variable also in your #interface, within the {}.
The answer for iPhone is NO. The compilers (both) can create that instance variable for you.
I hope that answers the question?
It is perfectly acceptable to do it this way. You would however need to implement the setter/getter methods yourself. These can not be created using the #synthesize syntax.
One reason to use this approach could be to have the properties based on something more complex than just setting and getting a value. It doesn't however make much sense for simple Nib connections as in your example.

Apple SeismicXML Example App

In the SeismicXMLAppDelegate implementation file of this class they have the following code:
// forward declarations
#interface SeismicXMLAppDelegate ()
#property (nonatomic, retain) NSURLConnection *earthquakeFeedConnection;
#property (nonatomic, retain) NSMutableData *earthquakeData; // the data returned from the NSURLConnection
#property (nonatomic, retain) NSOperationQueue *parseQueue; // the queue that manages our NSOperation for parsing earthquake data
- (void)addEarthquakesToList:(NSArray *)earthquakes;
- (void)handleError:(NSError *)error;
#end
Why do they have a second interface in the implementation file?
http://developer.apple.com/library/ios/#samplecode/SeismicXML/Listings/Classes_SeismicXMLAppDelegate_m.html#//apple_ref/doc/uid/DTS40007323-Classes_SeismicXMLAppDelegate_m-DontLinkElementID_10
This is a called an Extension (or an anonymous Category) in Objective-C
You can add properties, change its attributes and declare new methods like in that example.
Why not doing it in the interface file?
Well there could be a lot of reasons, for design purposes, for not to exposing some properties., etc.
For example, you cannot call myAppDelegate.earthquakeData from RootViewController.m even if you #import "SeismicXMLAppDelegate.h".
You can only access to earthquakeDataproperty from inside of SeismicXMLAppDelegate class.
You can read more about Categories and Extensions here: The Objective-C Programming Language

Core Data decorating with sort-compare methods

I have some NSManagedObjects and I would like to write methods for sorting and comparing the properties on them.
My problem is that since Core Data defines the properties as #dynamic they can not be referenced at compile time. This means that decorating an NSManagedObject with methods like this:
- (NSComparisonResult) compareDateAndTime:(Event *) event {
return [originDate compare:[event originDate]];
}
will result in the compiler not being able to locate a property called "originDate".
The above method is called like this:
NSArray *events = [[NSArray alloc]
initWithArray:[unsortedEvents sortedArrayUsingSelector:#selector(compareDateAndTime:)]];
I could go with predicates or fetchedResultController, but I would like to build these as
methods myself as I have an identical NSObjects for each NSManagedObject. This NSObject acts as a temp object that is passed around and populated before it's properties are set on the NSManagedObject that is then persisted. I also have some other functions, like specialized accessors, I would like to add to the NSManagedObject.
**(1)**Is there a general/best practice way of decorating NSManagedObjects with methods and functions **(2)**and have Xcode not overwrite them when "re-building" a class for an Entity?
Thank you for any help or "RTFM" given:)
I re-generate the model classes for my entities fairly often, so I added support methods (including implementations of getters for transient properties) as "Support" categories on the model classes.
I don't ever have to modify the model class files and there is no way I could accidentally overwrite my additional methods.
For example, a "Place" entity might have a name string and latitude/longitude numbers. It also could have a transient property for the first letter of the name. This can be used as the section name key path for section index titles in a large table view.
Xcode will generate the class files for the "Place" entity like this:
Place.h:
#import <CoreData/CoreData.h>
#interface Place : NSManagedObject
{
}
#property (nonatomic, retain) NSString * placeName;
#property (nonatomic, retain) NSNumber * latitude;
#property (nonatomic, retain) NSNumber * longitude;
#end
Place.m:
#import "Place.h"
#implementation Place
#dynamic placeName;
#dynamic latitude;
#dynamic longitude;
#end
I create a "Support" category on the "Place" class.
PlaceSupport.h:
#interface Place (Support)
- (NSString *)uppercaseFirstLetterOfName;
- (CLLocation*)location;
#end
and implement it in PlaceSupport.m
Can you use objectForKey:?
On the other hand, I haven't had a problem with using the properties directly in my code.