The "coordinate" property of MKAnnotation Protocol - iphone

My question is about the "readonly" attribute of the "coordinate" property. In the Protocol there is also a "setCoordinate" instant method listed. It says in the documentation that it is meant to support "dragging".
My question is :
1
If the coordinate can be set, then why there is a "readonly" attribute assigned to it ?
2
I am thinking of using a single temporary MKAnnotation object to populate an array. The scheme is to assign different coordinate values and add it to the array repeatedly. But the scheme would not work if the coordinate property is "readonly". Or can I use the "setCoordinate" for this purpose anyway ?
Am just wish to avoid having to create multiple MKAnnotation objects to populate the array (since the array can potentially be more that just a few points).
Hope that somebody knowledgable in this area could help ...
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKAnnotation_Protocol/Reference/Reference.html

The setCoordinate: method is optional. If your annotation supports dragging, you can implement it but you don't have to. The readonly property on the other hand is mandatory.
I am thinking of using a single temporary MKAnnotation object to populate an array. The scheme is to assign different coordinate values and add it to the array repeatedly. But the scheme would not work if the coordinate property is "readonly". Or can I use the "setCoordinate" for this purpose anyway ?
This scheme won't work in any case. If you add the annotation to your array, then modify the coordinate and add it again, you'll have the exact same annotation twice in your array, with the same coordinates. If you want an array of annotations with different coordinates, you will need to create a distinct annotation object for each coordinate.

Related

How to remove country/state names from MKMapview

I want to remove country / state names from MKMapview in iPhone. Means I need only blank map view without any name on it. Is this possible with MKMapview or any other third party maps.
I want to use this functionality with MKMapTypeStandard map type.
Have a look at MKMapViews property mapType MKMapTypeSatellite. Setting this type you will see a map without any names on it. See the docs:
MkMapView Class Reference
Code:
self.map.mapType = MKMapTypeSatellite;

Objective C convention: When to use For and when to use With

According to the Apple guideline , seems it is confusing, e.g. for method viewWithTag
In Java, I would have a method called
getViewByTag // Java version, equivalent to viewWithTag in Obj-C
But I also found there are some method like objectForKey, so why not just use objectWithKey instead?
getObjectByKey or just get // Java version, equivalent to objectForKey,
// but why not objectWithKey? Or not viewForKey above?
I actually think it is much simpler than what most answers think. I think it has less to do with complex programming language specifics, and has more to do with the uniqueness of the object in question.
When you say viewWithTag:, you are asking the UIView for any view that has that tag. There might be several. The UIView will return one of 'em.
However, objectForKey: (to me) sounds like there should be a single object (or nil) associated with that key. So, the key kinda exists and is bound (tightly coupled) to a single object.
EDIT:
There is an answer mentioning the existence of "by", which further implies how the convention has nothing to do with programming language complexities. It's just natural English.
NSString's stringByAppendingString:, for example, uses by, only because the function is written with a the verb appending. You can't say withAppending, that's bad English.
From my observation
While setting/getting the objects, you use WITH.
e.g. For setting of NSMutableArray object
- (id)initWithCapacity:(NSUInteger)numItems
While setting/getting the properties for objects, you use FOR.
e.g.For setting value for property of type NSMutableDictionary
- (void)setValue:(id)value forKey:(NSString *)key
Hope this helps in clearing your doubt
It seems like with is used for properties that directly belongs to an object. A UIView has a tag property so viewWithTag:14 could be rephrased as "Find the view whose tag property is 14".
When you put an object in a dictionary, associated to a key, this key is not necessarily part of the object itself. objectForKey:#"foo" is a way to say "Look for an object that's linked to the key "foo".
The Apple guidelines do not make any such claims as to when to use for or with. The point of the coding convention is to indicate what the types of the arguments may be and to write method signatures which are natural sounding.
The reason for the for or with in the method name is to identify the type or purpose of the first parameter to the method, which helps it read better.
Apple itself uses several conventions but that is the basic purpose, there is no concrete right or wrong just try to identify the first parameter of the method in the method name with either for or with.
And as for Apple conventions - get(whatever) is not even part of the actual conventions, so you could ask when do I use get or not.
Read this http://cocoadevcentral.com/articles/000082.php
also dont forget (by) NSURL urlByAppendingPathComponent etc - get a feel for it and you wont go wrong
You use "with" whenever the parameter is owned or to be owned, or will be a relatively permanent attribute by the object to the left of the "with" word.
initWithCapacity / arrayWithCapacity - the capacity will be an attribute of the container object being called and will be relatively permanent (until you add objects to it beyond the initial capacity)
viewWithTag – return a view "having" the specified "tag" attribute.
Whereas you use "for" to denote a looser association between the "desired" object and a "token" object that you use to get to it.
- objectForKey / attributeForValue – usually the "object" does not own the key.
- documentForWindow – the window is owned by the window controller and not the document. Furthermore there could be more than one window for each document.
But for looser associations of multiple
objects of the same type within a single method call, it's customary that you use something like:
doSomethingForFoo:withThisOtherFoo:havingYetAnotherFoo:
So the order for such complex call is:
for
with
having

Searching for particular MKAnnotation class in MKMapView

I have 4-5 kinds of different annotations classes in mapView.
With following code I expect only AnnotationType1 should respond to for loop.
for (AnnotationType1* annotation in mymap.annotations)
{
NSLog(#"annotation class is %#", [annotation class]);
}
But as is evident from console I get other classes also.
annotation class is AnnotationType1
annotation class is AnnotationType2
annotation class is AnnotationType3
annotation class is AnnotationType4
what will be the best way to perform actions only on say AnnotationType1 annotation?
First, as you've discovered, fast iteration doesn't work the way you thought it did. mymap.annotations returns the same array of annotation objects no matter what -- it doesn't have any idea what kind of pointer you're assigning them to.
Second, it's usually considered a bad idea to count on a view (such as MKMapView) to store data (like your annotations). It's fine for the map view to know about the annotations -- it must know about them to do its job properly. But I wouldn't recommend counting on the map view to maintain the app's state. You probably have the annotation objects stored somewhere in your data model -- if so, that'd be a better place to get the list of annotations.
Third, you can filter the array using a predicate. See this answer for help using a predicate to filter by class name.

adding objects to Mutable array

I want to add items to mutable array from a dictionary. Problem is I want to check existing array items before adding new item. If same item is already there in the array, I want to replace it. else add the new item.
How could I do it?
You could perhaps use an NSMutableSet rather than an NSMutableArray. The addObject method on NSMutableSet will only "add a given object to the set, if it is not already a member."
If you'd like to check membership before adding to the set anyway, you can check the result of:
[mySet containsObject:myObjectFromDictionary]
...which returns a simple BOOL value indicating whether the set already contains an object whose isEqual method returns true when your object is passed to it.
(For a little extra functionality, NSCountedSet will keep track of the number of objects added to the "set" for which isEqual: returns true)
You could compare the result of : [yourArray indexOfObject:yourObject]; against NSNotFound to know if the object is in the array.
It will give you the index of the object to replace, or if it is equal to NSNotFound, you will add it.
Objects equality is tested with isEqual: method.
NSArray class reference.
On the face of it, both Vincent's and Rich's answers are correct.
However, there is a conceptual issue in the original question that hasn't been addressed.
Namely, that "membership in an array" via indexOfObject: (or containsObject: in a set) is ultimately done by comparing the two objects using isEqual:.
If isEqual: returns YES, then the two objects better had damned well be functionally identical in your code or else you have other, significantly more serious, problems in your design and implementation.
Thus, the real question should be "How do I detect if an object is already in an array and not add it?" and Rich's and Vincent's answer are both still correct.
I.e. you should only need to check for presence and, if present, take no action.
(Note that there are esoteric situations where replacement is actually warranted, but they are both truly esoteric and not generally used within the context of a mutable collection)

Updating MKMapView Annotations from Updated array?

I am working with an NSMutableArray of objects that conform to the MKAnnotation protocol. My question is over time new objects are added to the array, can anyone tell me what is the preferred method for updating the annotations on the mapView. Should I be looking at removing all the pins before adding back the updated array, or would I be better to mark/tag existing pins in the MKAnnotation object and only add back the new (un-tagged) pins?
Removing all the pins and adding back the whole array including the new annotations will result in flicker and unnecessarily redrawing pins that haven't changed.
Unless the flicker is desired or a full refresh is necessary for some reason, it's better to just tell the map view to add the new pins.
After your main annotation array is updated with the new pins, construct a temporary array called say newAnnots containing references to the new annotations in the main array and pass newAnnots to the map view's addAnnotations: method. The temporary array can be discarded afterwards.
However, instead of using tagging to identify "new" annotations, you could just check if the annotation object in your main array already exists in the map view's annotations array. For example:
if (![mapView.annotations containsObject:annot_from_your_main_array]) {
[newAnnots addObject:annot_from_your_main_array];
}
Comparing with the map view's annotations array will only work if the annotation objects in your main array are the actual annotations you give to the map view in addAnnotation: or addAnnotations:. Also, when your main array is "updated", it should only add the new annotations instead of rebuilding the whole array from scratch. If it does, the annotation references won't match with the ones in the map view's array.
The same applies if you are removing annotations on an update. The removed annotations could be added to a temporary "remove" list (by checking if annotations in the map view's array exist in your array) and passed to removeAnnotations:.
Note that if you update an existing annotation's coordinates in your main array, the map view will automatically update the pin's location as long as the annotation object in your array implements the setCoordinate: method.