3

I am going through the tutorials provided by Apple and tried to improve "My Second iOS App", the app for bird sightings. (There is a MasterView where all entered sightings are listed. If you click one, you are directed to a DetailView of the sighting. You can add a sighting and are asked to enter a name and location.)

I want to sepperate the views for entering the birds name and location.

So I have two views (one for entering the name and one for entering the location) and one object I want to store.

In the file BirdSighting.m I added the following methods

-(id)initWithNameOnly:(NSString *)name date:(NSDate *)date
{
    self = [super init];
    if (self) {
        _name = name;
        _date = date;
        return self;
    }
    return nil;
}

and

-(id)setLocation:(NSString *)location
{
    if (self) {
        _location = location;
        return self;
    }
    return nil;
}

In the AddSightingNameViewController.m I implemented the following code

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"ToLocation"])
    {
        if ([self.birdNameInput.text length])
        {
            BirdSighting *sighting;
            NSDate *today = [NSDate date];
            sighting = [[BirdSighting alloc] initWithNameOnly:self.birdNameInput.text date:today];
            self.birdSighting = sighting;
        }
    }
}

The view for entering the name leads with a push segue to the location-view. There has'nt been changed much else.

Now how do I pass the object generated in the first view to the second? And how do I call the setLocation method on this specific object in AddSightingLocationViewController.m? Do I have to define different properties? And how do I finally display the object in the MasterView with the correct data after I entered the location?

As this code is not working yet, I don't even know if it is working, what I am trying to do. So please be gentle, if this is crappy code.

Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
RNelke
  • 87
  • 7
  • possible duplicate of [Using object from one class in another](http://stackoverflow.com/questions/15187241/using-object-from-one-class-in-another) – Anoop Vaidya Mar 04 '13 at 10:50
  • Sorry, the answer to your linked question and the links in it didn't help me. Maybe I am to much of a beginner to see the relation to my problem. – RNelke Mar 04 '13 at 11:01
  • As your main doubt is **Now how do I pass the object generated in the first view to the second?** and that link solves that issue – Anoop Vaidya Mar 04 '13 at 11:05
  • This is about changing a label of a different view. There is this use of `NSNotificationCenter` but I don't see how to retrieve the object in the receiver view. – RNelke Mar 04 '13 at 11:15
  • if you send by notification, then the reciever gets an object that contains the sender object with values. so you can get the value in the observer class – Anoop Vaidya Mar 04 '13 at 11:19
  • I am very new to iOS development in general. I'd apreciate an answer that is directly related to my problem. I do not see how I should use `NSNotificationCenter` in the second view to get an object I can work with. The developer library shows also no example for it. I am mostly missing an allocation like `newObject = oldObject`. And is it then possible to go on like `[newObject setLocation]`? – RNelke Mar 04 '13 at 11:32

1 Answers1

2

This is the method I have been using:

First you will need to add a property in your destination view controller, to hold the object you want to pass:

@property (strong, nonatomic) BirdSighting *newSighting;

Then change the prepareForSegue method in your first view controller to the following:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"ToLocation"])
    {
        if ([self.birdNameInput.text length])
        {
            BirdSighting *sighting;
            NSDate *today = [NSDate date];
            sighting = [[BirdSighting alloc] initWithNameOnly:self.birdNameInput.text date:today];
            self.birdSighting = sighting;

            // Get destination view
            YourDestinationViewController *vc = (YourDestinationViewController *)segue.destinationViewController;

            // Pass birdSighting object to your destination view controller
            [vc setNewSighting:self.birdSighting];

        }
    }
}

I think I originally got this method from this question

It is also worth noting that the BirdSighting class has a location @property in it's .h file & you will notice the @synthesize line in the .m file.

The @synthesize directive automatically creates accessor methods for you:

@property (nonatomic, copy) NSString *location;

Has the following methods automatically generated (but not visible in the file):

- (NSString *)location;

- (void)setValue:(NSString *)location;

Therefore it was unnecessary for you to override the setter method for location in the BirdSighting.m file with:

-(id)setLocation:(NSString *)location

If you remove that method (note that it should return void not id) you should now be able to access the location variable in a BirdSighting object in the following way:

// In this example we are accessing a BirdSighting @property (hence the use of self.sighting)
// @property (strong, nonatomic) BirdSighting *sighting;

// Getter - returns (NSString *)location of the BirdSighting object
[self.sighting location];

// Setter - sets the location property of the BirdSighting object to 'newLocation'
[self.sighting setLocation:newLocation];

Hope this clears some things up for you!

Community
  • 1
  • 1
Pliskin
  • 1,259
  • 10
  • 11
  • Thank you very much! Especially for the code snippet related to my problem. One tiny thing: You aren't allowed to call the property "newSighting", I get en error message related to naming conventions. The rest works so far. One Question remains: How do I retrieve and work with the object in my destination view? so I can do something like `[retrievedObject setLocation]`. – RNelke Mar 04 '13 at 13:19
  • What was the error message? Did you declare the newSighting property in the .h file of the destination view controller? ... you should be able to access the object in your destination view with `[self.newSighting setLocation];` – Pliskin Mar 04 '13 at 13:28
  • Sorry that last bit should be `[self.newSighting setLocation:location];` – Pliskin Mar 04 '13 at 13:41
  • ...& to retrieve the location `[self.newSighting location];` note that when you create a property foo it synthesises the setter method `-(void)setFoo:(Type *)foo` and the getter method `-(Type *)foo` it was unnecessary for you to override `-(id)setLocation:(NSString *)location` – Pliskin Mar 04 '13 at 13:57
  • The error message was: _porperty's synthesized getter follows Cocoa naming conventions for returning 'owned' objects_. Just changing _new_ into something else helped. But still `BirdSighting *sighting = self.initialSighting; sighting = [sighting setLocation:self.birdNameInput.text];` doesn't work. Error message is: _Receiver type 'BirdSighting' for instance message is a forward declaration_. Oh, and I found out about the automatic genereation of the setter meanwhile on my own. Thanks nonetheless :). – RNelke Mar 04 '13 at 14:07
  • The error message: _instance message is a forward declaration_ typically means that you the compiler didn't know about the declaration of the class, i.e. you haven't included the proper header. In your case write `#import "BirdSighting.h"` at the beginning of the file you are getting the error in. – Pliskin Mar 04 '13 at 14:36
  • Let me know if that works..If my answer answers your initial question I would appreciate you 'accepting' my answer by clicking the little 'tick' by the top of my question :) – Pliskin Mar 04 '13 at 14:51
  • Of course! I forgot to import the header file. But now the error message says: _Assigning to 'BirdSighting *__strong' from incompatible type 'void'_. Why is `initialSighting` recognized as void? But thank you very much for your detailed answers so far! – RNelke Mar 04 '13 at 14:58
  • Your problem lies in: `sighting = [sighting setLocation:self.birdNameInput.text];` In objective-C `[sighting setLocation:self.birdNameInput.text];` does the assignment you do not need `sighting =`. – Pliskin Mar 04 '13 at 15:08
  • Alternatively because location is a property you can use the dot notation: `sighting.location = self.birdNameInput.text` – Pliskin Mar 04 '13 at 15:13
  • Argh, of course, what you wrote before was correct. I mistyped and it should be `birdLocationInput`. And now everything works fine. Thank you very much indeed! You helped me alot. – RNelke Mar 04 '13 at 15:23