MKAnnotation or MKMapItem - objective-c

What's the difference between MKAnnotation and MKMapItem?
Which one to use when I want to display some interesting places on my map?
I have a list of objects that have latitude, longitude, title, description and photo so far and I'd like to have them on my map.

MKAnnotation is a MARKER meant for displaying stuff using a MKAnnotationView
so the procedure is:
add a MKAnnotation to let the map know that there is an entry
wait for the map's delegate call viewForAnnotation
set up a annotationView there that is to be shown
a good tutorial (IMO) that shows this with detailed code is at: http://www.codigator.com/tutorials/mapkit-tutorial-for-ios-beginners/
MKMapItem is only for the openMapWithItem api that opens the external app!
EDIT: MKMapItem has a placemark property which is a MKAnnotation - so if that's non-nil you can add it. (note that it might be nil)

MKAnnotation is a protocol, used to provide annotation-related information to a map view.
I think what you really meant to refer to was a MKAnnotationView, which is used to "present annotations visually in a map view".
A MKMapItem "encapsulates information about a specific point on a map. This information includes the map location and any other data that might be relevant, such as the name of a business at that location. Apps use this class to share map-related data with the Maps app."
If you want to show annotations for a specific point on your map, I suspect what you want to do is use a MKAnnotationView.

Related

The removeAnnotations for MKMapView

Why is it so useful to delete annotations?
[self.mapView removeAnnotations:[self.mapView annotations]];
It doesn't work.do this:
[self.mapView removeAnnotations:self.mapView.annotations];
The system definition:
- (void)removeAnnotations:(NSArray<id<MKAnnotation>> *)annotations;
If the question is really WHY, this is what you can find reading the official documentation :
If the annotation is currently associated with an annotation view, and
that view has a reuse identifier, this method removes the annotation
view and queues it internally for later reuse. You can retrieve queued
annotation views (and associate them with new annotations) using the
dequeueReusableAnnotationViewWithIdentifier: method.
Removing an
annotation object disassociates it from the map view entirely,
preventing it from being displayed on the map. Thus, you would
typically call this method only when you want to hide or delete a
given annotation.

How to create an extended MKMapView

I have an app which uses maps on several different screens. All the maps should display the same basic information (annotations and overlays), but every instance adds different additional annotations and overlays to the map. I want to create a class, which implements the common features and behaves exactly like the MKMapView. How is this possible?
I've had three ideas to solve this, but none of them seems to be a good solution.
Subclass MKMapView. The problem with this approach is that the map gets the information about it's annotations and overlays from it's delegate, which should be the subclass (a view...) itself, therefore adding additional data is problematic (I can't set the delegate other than the class itself).
Wrap MKMapView. I could create an NSObject/UIView subclass which has an MKMapView, but either I have to proxy all of the map's methods to my class or access the map with a knowledge of the inner objects (myMapView.mapView.xxx...).
Create a delegate class (NSObject with MKMapViewDelegate functions). The delegate class could then implement the common behavior. This solution also has issues similar to the first one.
How can I solve this elegantly?
Create a class and Add Map to view of that class.
Now make that class as parent class for all class where you want to add Mapview.
Provide data to parent class when you want to add annotations and overlays.

Objective-C: Refactoring code - how do I get a pointer to a view instance?

I am not very experienced with OOP so I wanted to share what I am currently doing and ask for some advice about how I should go about a couple of things.
I am currently working on a simple game that uses a 2d grid. Here is a quick overview of my class structure:
'GameBoard'- has an array of the possible cell states for the game, and methods that implement the rules.
'GameView' - has the superclass NSView, and is placed in my window as a custom view. This class is intended to read from the game board and draw the contents of the array by mapping the stares to an enumeration of images in its drawRect: method.
'GameController' - this is an intermediate class intended to initialise the game board and view, and handle the various UI controls. This class has instance variables of the 'GameBoard' and 'GameView' type.
Originally, I was doing nearly everything in the View class, and had it working fine but it started to get hard really to follow, which was my main reason for wanting to spread my code over a new class.
I have created a method in 'GameController' that initialises a new game, with some user defined parameters (removed in the snippet to save space).
-(IBACTION)initialiseGame:(id)sender {
gameBoard = [[GameBoard alloc] init...];
gameView = [[GameView alloc] init...];
}
What I want to do here is pass the game view a pointer to the game board instance so that I can read it's array to draw the current state of the game, something like:
-(void)initWithGameBoard:(GameBoard*)gameBoard;
Is this the right way of going about that, or should I be doing this in a different way?
My next problem with moving to the controller class is that I cannot seem to find out how to do is get a pointer to the instance of GameView that I have placed on the window in IB? Would it be better to not place the view on the window in interface builder, and instead place it on the window programatically in the initialiseGame function? If so how would I go about doing that?
I guess one other question would be, should I just scrap this idea and stick to doing everything in the GameDraw class?
Thank you very much for taking your time to read this, this is probably a very simple question to any experienced object-oriented programmer, but I cannot seem to find the answers specifically anywhere.
There's more than one way to do make this work, but here's how I would do it:
Instantiate the view once in IB. Don't invoke alloc/init yourself.
In your view controller, make an outlet for your view and connect it in Interface Builder. That's how your controller will get access to it. Your view controller will need to be the file owner — probably it already is.
Design the view to be reusable. Give it a -setGameBoard: method for the controller to invoke. Make sure the view can draw something blank when it doesn't have a game board.
Write -initializeGame: like this:
-(IBAction) initialiseGame:(id) sender {
gameBoard = [[GameBoard alloc] init...];
[gameView setGameBoard:gameBoard];
}

Assist me understand ABPeoplePickerNavigationController Class

I am working on iOS Address Book but having some issues, I am referring the iOS programming guide which says
Prompting the User to Choose a Person Record:
The ABPeoplePickerNavigationController class allows users to browse their
list of contacts and select a person and, at your option, one of that
person’s properties. To use a people picker, do the following:
Create and initialize an instance of the class.
Set the delegate, which must adopt the ABPeoplePickerNavigationControllerDelegate protocol.
Optionally, set displayedProperties to the array of properties you want displayed. The relevant constants are defined as integers; wrap
them in an NSNumber object using the numberWithInt: method to get an
object that can be put in an array.
Present the people picker as a modal view controller using the presentModalViewController:animated: method. It is recommended that
you present it using animation.
Point one says Create and initialize an instance of the class, its init methods includes withnibname other property is inputview, can this be used to customize address book gui?
point three is also pointing towards displayedProperties, address book gui can be modified?
Like whatsapp, viber, etc .. I also want to customize the address book
so I can also display status under contacts name, so I can display
custom image as accessories etc etc. Please check the screenshots.
I believe they are not using the build in ABPeoplePickerNavigationController Class.
They fethc all the users from the address book and populate it into a table view.
I don't know of any way to customize the ABPeoplePickerNavigationController Class.

iOS storyboard: how to handle dynamic, floating content?

My App contains a news-section. I'm trying to create a View in my storyboard which will show an news item. A news contains of a title, a date, an image, and some text.
Content like this would be easy to display in HTML since it's content is floating, but as far as I understand iOS elements have a fixed size. I think a UILabel could be fine for title and date, UIImage for the image and a UITextView for the text. I think all elements should be inside a scroll view. The problem is, that the title for some news will fill one line but for other news multiple lines.
How can I handle a setup like this in a storyboard? A link to a guide, tutorial would be fine.
There are a lot of different ways you could approach this. Ultimately you have control of the size of any of these elements at runtime. From a UX point of view you'd probably want to keep at least some of the elements fixed in size (e.g., the image and the scrollview representing the total size of the news item). That would leave playing with the relative sizes of the title and the detail. If you want to show the entire title you can use the sizeWithFont method (or one of its variations) of the NSString class to calculate how much space to use for the title, and allocate space from the remaining amount to the detail as desired.
UPDATED: I might add that I intended this as a general strategy, not specifically aimed at the new iOS 5 Storyboard functionality.
UPDATED: Well, no tutorial but here are some general guidelines (at least about the way I might tackle it).
I'd set up a NewsItem class that encapsulates the elements that you describe here, similar to what I've laid out in the example image. How you expose NewsItem is something of a matter of taste; you might want to start with a UITableView as a container as it would make managing a NewsItem collection simpler. I'd subclass UITableViewCell as NewsItemTableViewCell, and generate a nominal layout for a NewsItem using Interface Builder. So in the example image, a news item would correspond to one table row.
The main part that you are asking about is identified by the red and blue frames in the image. Using the above approach, I would add logic in the NewsItemTableViewCell to calculate the extent of the title -- this assumes that the View (in this case, the NewsItemTableViewCell) has explicit knowledge of the Model (the underlying data for the news item) in the form of a reference (i.e, an instance of a NewsItem class
that contains the items you've described retrieved from a web service). If the width of the title is greater than the default width of the red frame, I'd adjust the height of the red frame (increasing it) at the same time decreasing the height of the blue frame. This kind of approach avoids having to include extra logic for differing cell heights within the table.
An alternative I often use is to have a Controller class mediate between the View and the Model. This can be useful when you have a requirement that your table contain different kinds of cells; it also makes tableview cell reuse much simpler. In this case, declare a base class. This might look something like:
#protocol GenericCellController
- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath;
#optional
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath;
#end
and then:
#interface NewsItemTableCellController : NSObject<GenericCellController> {
NewsItem* newsitem;
}
You then set up a collection of table cell controller objects. This has the advantage that when you implement tableView:cellForRowAtIndexPath: in your tableview controller code, you only have to delegate to the cell controller object at the appropriate row. What's more, you can refer to it using a superclass designation; e.g., in a hypothetical NewsItemTableViewController class you might have:
- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*) path {
NSObject<GenericCellController>* cellController = [cellControllerArray objectAtIndexPath:indexPath.row];
UITableViewCell* cell = [cellController tableView:tableView cellForRowAtIndexPath:indexPath];
return cell;
}
This approach allows you to have any class derived from NSObject in the collection and polymorphically use delegation to have the derived class handle the rendering logic. The derived Controller class has its own implementation of tableView:cellForRowAtIndexPath: with a corresponding UITableViewCell-derived subclass as described above.
If you decide to go this way, there are numerous examples of the basics of tableviews and their controllers that you can use as a preface to implementing these ideas.