MKAnnotation protocol - iphone

Im currrently going through a geolocation tutorial which adopts the MKAnnotation Protocol into a class.
The tutorial suggests to create the following methods in the Theannotation.h class
+ (id)annotationWithCoordinate:(CLLocationCoordinate2D)coord;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord;
and in the implementation
+ (id)annotationWithCoordinate:(CLLocationCoordinate2D)coord {
return [[[[self class] alloc] initWithCoordinate:coord] autorelease];
}
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord {
if ( self = [super init] ) {
self.coordinate = coord;
}
return self;
}
The second method is then called in a viewcontroller
Theannotation *annotation = [[SimpleAnnotation alloc] initWithCoordinate:Coords];
I understand the second method completely however Im puzzled to the inclusion of the first. The class method isn't called at any other place in the example tutorial and im struggling to understand why you would use a class method in this case.

You can omit this class method but in some cases it is useful because it provides you a mechanism to create 'temporary' annotation that will be autoreleased. Of course you can do it manually, but class method is a way of convenience in that case.

please go through this blog here
or you can download the code-
link
and see the code, you will know that which things are mandatory and which will not.

Related

NSManagedObject Incompatible pointer type warnings

Let me make sure first I have X-Code 4.3.2 version and iOS 5.1 SDK. I have below methods used in my project for core-data operation. Both method giving same warning. i.e "Incompatible pointer types returning 'NSManagedObject *' from a function with result type 'NSManagedObject <Protocol> ".
Method A:
- (NSManagedObject<Protocol> *)newMOforNilMOC
{
return [[NSManagedObject alloc] initWithEntity:[self entityDescription] insertIntoManagedObjectContext:nil];
}
For method method A I just do typecasting and added (NSManagedObject<Protocol>*) then warning get removed as stated below.
- (NSManagedObject<Protocol> *)newMOforNilMOC
{
return (NSManagedObject<Protocol> *) [[NSManagedObject alloc] initWithEntity:[self entityDescription] insertIntoManagedObjectContext:nil];
}
Method B:
+ (NSManagedObject<Protocol> *) newInContext:(NSManagedObjectContext *)context
{
return [[NSEntityDescription insertNewObjectForEntityForName:[[(NSManagedObject<Protocol> *)self class] entityName] inManagedObjectContext:context]retain];
}
For method B when I do typecasting it will not work hence I just change the name of method from newInContext to AddnewInContext (Found somewhere when googled) then warning got removed.
I have following Questions:
If first method is required typecasting then why second one is not working with that solution?
What is the exact meaning of changing the name of method. Is this proper way to remove above warning? Why typecasting not working in
method B?
This could be complicated one but feel free to leave comment if you have any doubt. Because I want to know the difference, at least I get to learn some new thing about core data.
I think you are using 'self' in a class method. You should use the class itself. Let me show by code
+ (NSManagedObject<Protocol> *) newInContext:(NSManagedObjectContext *)context
{
//Usage of [self class] is not correct, as self points already to a class.
NSEntityDescription* desc = [NSEntityDescription entityForName:#"myObjectName" inManagedObjectContext:context];
return [[NSEntityDescription insertNewObjectForEntityForName:desc inManagedObjectContext:context]retain];
}
You can't cast a class type to a 'id' type, which is the one that self points to if you are inside an object method, not a class method. I don't think any method renaming solves any warning.

objective-c call function from another class

I have a function on a class "loadingViewController" that needs to be accessed from other classes. First time that I call function like follows, it works but if I then call it again from another class do not because allocates it again and reset parameters. Same if I create an instance method. How to simply call a function from another class without init or allocate again? Probably basic newbie issue... Thanks.
class was declared in header and properly synthesized.
self.loadingController = [[loadingViewController alloc] initWithNibName:#"loadingViewController" bundle:nil];
[loadingController incrementProgress:0.1];
Hard to say for sure without seeing more code, but I'm thinking you just need to make sure you only initialize the loadingController once:
if ( self.loadingController == nil ) {
self.loadingController = [[loadingViewController alloc] initWithNibName:#"loadingViewController" bundle:nil];
}
[self.loadingController incrementProgress:0.1];
You can implement protocols here. Protocols are used to call methods of another class from one class. In general it will define the set of methods which your class will implement. TO see how to implement it you can see this answer.
I would do this:
-(void) loadingViewController
{
if ( self.loadingController == nil ) {
self.loadingController = [[loadingViewController alloc] initWithNibName:#"loadingViewController" bundle:nil];
}
[self.loadingController incrementProgress:0.1];
}
AND make sure you don't call [xyz loadingViewController] from any other thread than the main UI thread.
It looks like the reason you want to call a function on a view controller is to present the progress of a long operation to the user.
The more common approach is to have the view controller start the operation and then observe it's progress, updating the view accordingly.

calling a method of current class from a method of another class

I am working on a class A which has a method -(void)DoSmthing1. I am making a call to
another method-(void)DoSmthing2 in class B. Now after doing some operations in class B, the method is supposed to call back a method-(void)DoSmthing3 previous class.
How will i call a method of current class from another class?? Can someone please help me....
Thanks in advance
edit1::
My Code:
Class A
{
-(void) MethodA {
}
-(void) MethodB {
ClassB *clsB = [[ClassB alloc] init];
[clsB MethodC];
}
}
Class B
{
-(void)MethodC:(selector) {
//here i want to call MethodA of classA, and i will prefer if it is possible by sending the name of the method as selector in this method(methodC)
}
}
edit2::
Another example i want to do smthing like follwoing:
ClassB *b = [[ClassB alloc] nitWithTarget:self selector:#selector(methodfromClassA) object:nil];
Here i want to call a method of class A once some task in Class B is completed, and that too from class A.
I hope it is much clear now.
Edit3:
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async getAsync:self callback:#selector(test1)];
}
above code is from first class
-(void)getAsync:(id)anObject callback:(SEL)selector {
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:anObject
selector:#selector(selector)
object:nil];
[queue addOperation:operation];
[operation release];
}
and above code is from second class. Here i want to call a method of first class which is passed as selector.
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async getAsync:self callback:#selector(test1)];
}
Other class:
-(void)getAsync:(id)anObject callback:(SEL)selector {
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:anObject
selector:#selector(selector)
object:nil];
[queue addOperation:operation];
[operation release];
}
First, if you want to use the above pattern, remove the #selector() from #selector(selector). You already have the selector. Doing #selector(selector) will create the SEL named selector and not the selector passed in as the argument.
Next, this seems like an odd pattern to start with; it'll work, but any experienced Obj-C/iOS/Cocoa developer will get the willies looking at it. Since you wrote the AsyncConnection class, use the delegate pattern. I.e. in the class that implements loadView.
That is, in AsyncConnection.h:
#property(retain) ClassA *callbackHandler;
And then:
- (void)loadView {
AsyncConnection *async =[[AsyncConnection alloc] init];
[async setCallbackHandler: self];
}
Then, in AsyncConnection, you would refer to the callback handler directly as self.callbackHandler (or [self callbackHandler]).
It sounds like you would benefit from reading the introductory material: The Objective-C Programming Language and Cocoa Fundamentals Guide. Additionally, you should read up on the basics of object-oriented programming (there are dozens of overviews all over the web and Amazon).
Essentially, you're confusing a class (the blueprint for creating an object, in its most basic description) and an instance of a class (an actual "instantiated" object of a given class). Somewhere you're going to have to have a reference from one instance to another (like objectB = [[ClassB alloc] init]) to send a message (like [objectB doSomethingAnObjectOfClassBWouldDo]). You might accomplish this by storing the reference as an instance variable or inside a collection (array, dictionary, etc.) that is an instance variable of the class that needs to "remember" who it needs to talk to.
It's important to realize you're trying to walk before you've learned to crawl with this platform. The only cure is to study. A lot. Guided books help.
Then new approach:
Should be something like:
classB.h
classA *aObj;
#property(nonatomic, retain) classA *aObj;
classB.m
#synthetize aObj;
classA.m
// after init class b obj
[bOjb setAObj:self];
classB.m
[aObj whateverMethodOfClassA];
Let me know if not clear.
My sugestion, is that generally if you want to avoid a real mess and a nightmare to debug, you should use observers and notifications rather than this kind of cross methods calls.
Make class A an observer of a notification of class B:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(classA-method-name:) name:#"notification-name" object:class-B-object ];
And when ready in class-B notify class A with parms:
[[NSNotificationCenter defaultCenter] postNotificationName:#"notification-name" object:self];
Just an idea.
One option is to use the delegate pattern in Objective C. Have the object of class A pass itself to an object of class B to be the handler for certain methods.

Apple Singleton example query?

I am a little confused by this snippet of code (presented in the CocoaFundamentals guide) that overrides some of the methods when creating a singleton instance.
static id sharedReactor = nil;
+(id)sharedInstance {
if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init];
return sharedReactor;
}
.
+(id)allocWithZone:(NSZone *)zone {
return[[self sharedInstance] retain];
}
-(id)retain {
return self;
}
In the code where the singleton instance is created the +sharedInstance method calls [super allocWithZone:NILL] from the superclass (which in my case is NSObject) The allocWithZone above is only called if you attempt to use it to create a new singleton.
The bit I am confused about is the use of retain, especially seeing as retain is also overridden to return self. Can anyone explain this, could it not be written:
+(id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(id)retain {
return self;
}
EDIT_001:
Based on comments and reading various posts on the web I have decided to go with the following (see below) I have chosen to go for a shared singleton approach where if needed I would have the option of creating a second or third instance. Also at this stage as I am only using the singleton for the model portion of MVC for a simple iPhone app I have decided to leave thread safety out. I am aware its important and as I get more familiar with iPhone programming I will likely use +initialize instead (keeping in mind the subclass issue where it can be called twice) Also I have added a dealloc, firstly to log a message should the singleton be released, but also to clean things up properly should the singleton be no longer required.
#interface SharedManager : NSObject
+(id)sharedInstance;
#end
#implementation SharedManager
static id myInstance = nil;
+(id)sharedInstance {
if(myInstance == nil) {
myInstance = [[self alloc] init];
}
return myInstance;
}
-(void)dealloc {
NSLog(#"_deal: %#", [self class]);
[super dealloc];
myInstance = nil;
}
#end
In testing I found that I had a set the static variable to nil in the dealloc or it maintained its pointer to the original object. I was initially a little confused by this as I was expecting the scope of the static to be the instance, I guess its the class instead, which makes sense.
cheers gary
First, don't use this code. There is almost never a reason to do all this for a simple singleton. Apple is demonstrating a "Forced Singleton," in that it is impossible to create two of them. It is very rare to really need this. You can almost always use the "shared singleton" approach used by most of the Cocoa objects that have a singleton constructor.
Here's my preferred way of implementing shared singleton:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] init];
}
return sharedManager;
}
That's it. No other code is required. Callers who use +sharedManager will get the shared instance. Callers who call +alloc can create unique instances if they really want to. This is how such famous "singletons" as NSNotificationCenter work. If you really want your own private notification center, there is no reason the class should forbid it. This approach has the following advantages:
Less code.
More flexible in cases where a non-shared instance is useful.
Most importantly: the code does what it says it does. A caller who thinks he's making a unique instance with +alloc doesn't encounter surprising "spooky action at a distance" behavior that requires him to know an internal implementation detail of the object.
If you really need a forced singleton because the object in question maps to a unique resource that cannot be shared (and it's really rare to encounter such a situation), then you still shouldn't use +alloc trickery to enforce it. This just masks a programming error of trying to create a new instance. Instead, you should catch the programming error this way:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] initSharedManager];
}
return sharedManager;
}
- (id)init
{
NSAssert(NO, #"Attempting to instantiate new instance. Use +sharedManager.");
return nil;
}
// Private method. Obviously don't put this in your .h
- (id)initSharedManager
{
self = [super init];
....
return self;
}
There is a good example of different singleton methods with comments here on SO:
What does your Objective-C singleton look like?
If it helps, the example has a different approach to allocWithZone: which returns nil.

understanding TTNavigator

following situation:
in a TTTableViewController i added some Cells with URLs.
they are opening a class with #"tt://photos" for example. this works quite fine.
the first thing is, i saw some urls in TT Examples like #"tt/photos/1". is it possible to fetch this "1" in my photos class and say, for example okay, please open picture one, ore is this only another URL that was declared in TTNavigatior to open a specific Class?
the other thing is: is it possible to forward an object to the linked class?
clicking a cell opens #"tt://photos" (the linked class in my TTNavigator)
working with normal tableviews i can overwrite my init method and send an object with my initialize method, is this also possible by clicking my TTItems?
thanks!
figured it out myself, for those who need it:
First (passing "subURLs" in your navigator map)
navigating to an URL with #"tt://photos/firstphoto" is possible, you can fetch the "firstphoto" like this:
//Prepare your Navigator Map like this
[map from:#"tt://photos/(initWithNumber:)" toViewController:[PhotoVC class]];
In your PhotoVC you can access this Number:
-(void) initWithNumber: (NSString*)number {
NSLog(#"%#",number);
}
calling your View Controller with this url would look:
PhotoVC* controller = [[PhotoVC alloc] initWithNumber:#"1"];
[navigationController pushViewController:controller animated:YES];
[controller release];
Second (passing objects in an TTTableViewController)
its a bit tricky, but you dont have to Subclass anything.
first, nil the URL in the TableItem
[TTTableLink itemWithText:#"TTTableLink" URL:nil]
in your TTTableViewController write down this method
- (void)didSelectObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
TTURLAction *urlAction = [[[TTURLAction alloc] initWithURLPath:#"tt://photos"] autorelease];
urlAction.query = [NSDictionary dictionaryWithObject:#"firstphoto" forKey:#"photo"];
urlAction.animated = YES;
[[TTNavigator navigator] openURLAction:urlAction];
}
now in your your PhotoVC you need something like this
- (id)initWithNavigatorURL:(NSURL*)URL query:(NSDictionary*)query {
if (self = [super init]) {
NSLog(#"%#",query);
}
return self;
}
and you are done ;)
I was trying to implement choise's answer, learned a lot, and eventually had to get the callouts showing up and keep the implementation with many urls simple, so here's what i did.
Keep URL in the TableItem,
Use this code in the TTTableViewController subclass.
- (void)didSelectObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
NSLog(#"Its url is %#", [object URL]);
TTURLAction *urlAction = [[[TTURLAction alloc] initWithURLPath:(NSString *)[object URL]] autorelease];
urlAction.query = [NSDictionary dictionaryWithObject:self.user forKey:#"user"];
urlAction.animated = YES;
[[TTNavigator navigator] openURLAction:urlAction];
}
- (BOOL)shouldOpenURL:(NSString*)URL {
return NO;
}
That "shouldOpenURL:" was discovered looking through TTTableViewController, I tried it out, and it worked. Now the table view is not opening a duplicate view, and there are callouts!
Thanks choise!
Although choice's answer works for multiple params when u are creating the TTURLAction in code it is not very useful when u want to embed links to view controllers in your TTStyledLabel.One solution to that is to use multiple params in a single string.
<a href='app://view2/param1=value1&param2=value2&...'>LabelName</a>
if you want the code to parse such urls and get the params please feel free to send me a message and I will send you my parser classes.
(or you can build your own with NSScanner!)
Also dont forget to escape the &s otherwise TTStyledLabel would not like it!
You don't need to run this on current version 1.0.6.2 for TTTableViewController. The "URL" option is working as expected. If it's not working for you, then your URL is broken or your are calling the wrong function on your ViewController. The function you have to call through URL must return an id (be a constructor for a ViewController) of a ViewController. Then it'll work as expected.
I'll changed the example form choise to be like TTNavigator expect it to be.
Add a mapping, which TTNavigator will use to navigate:
//Prepare your Navigator Map like this
[map from:#"tt://photos/(initWithNumber:)" toViewController:[PhotoVC class]];
Create a TTTableLink (or TTStyledText, or other) with an URL set, which should mach your map:
[TTTableLink itemWithText:#"TTTableLink" URL:#"tt://photos/1"]
Add this to your PhotoVC to be called by TTNavigator on the given URL
-(id) initWithNumber: (NSString*)number {
if (self = [super init]) {
self.title = #"Some Title";
NSLog(#"%#",number);
}
return self;
}
You don't need to overwrite the function didSelectObject, as the TTNavigator will call your ViewController through defined constructor function tt://photos/(initWithNumber:)