I hope you can help me with the following problem in Objective-C. I´ve been sitting around for two hours now, but I have no idea what´s wrong.
Here´s my code:
BMICalc.h:
#import <UIKit/UIKit.h>
#interface BMICalc : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property (strong, nonatomic) NSMutableArray *bmiArray;
-(int)bmiRows;
#end
BMICalc.m:
#import "BMICalc.h"
#implementation BMICalc
#synthesize bmiArray;
- (int) bmiRows
{
if (!bmiArray)
{
bmiArray = [[NSMutableArray alloc] init];
}
return [bmiArray count];
}
#end
Now I want to create a object of BMICalc in another class called BMIDiaryController:
BMIDiaryController.m:
#import "BMIDiaryController.h"
#import "BMICalc.h"
#interface BMIDiaryController ()
#end
#implementation BMIDiaryController
- (void)viewDidLoad
{
[super viewDidLoad];
BMICalc *bmiSender = [[BMICalc alloc] init];
int bmiVariable = [bmiSender bmiRows];
}
#end
So when I start the programme i get the following error:
"No visible #interface for 'BMICalc' declares the selector 'bmiRows'
I can´t call the method "bmiRows" with the object "bmiSender" (both of Class "BMICalc"
I hope you can help me with this. I searched and searched...I think it´s just a small thing, but I won´t see it...
Thank you and regards,
Stefan
Try creating a new project. Then add the BMICalc.m and BMICalc.h files. Try to instantiate your BMICalc object and call the bmiRows method from the appDelegate just to test it. There could be any number of things wrong in your main project that may be interfering with the class. At least doing this will confirm that you aren't crazy and that this code isn't the problem :)
Related
I am in ViewController, trying to access a method in object "cat" owned by object "backgroundpicture". ViewController has an instance of backgroundpicture.
The method/message in "cat.h":
#interface Cat : NSObject
-(BOOL)checkIfTouchHit:(float) xx :(float) yy;
#end
"Cat.m":
- (BOOL)checkIfTouchHit:(float) xx :(float) yy{
NSLog(#"Inside checkIfTouchHit");
return YES;
}
"BackGroundPicture.h":
#import "Cat.h"
#interface BackGroundPicture : NSObject
#property (strong) Cat * katt;
#end
"BackGroundPicture.m":
#implementation BackGroundPicture
#synthesize katt = _katt
#end
"ViewController.m":
#interface ViewController ()
#property (strong) BackGroundPicture * bakgrunnsbilde;
#end
#implementation BackGroundPicture
#synthesize bakgrunnsbilde = _bakgrunnsbilde;
- (void)viewDidLoad
{...
[[self.bakgrunnsbilde katt] checkIfTouchHit :(float)touchLocation.x :(float)touchLocation.y]
...}
The string inside the method "checkIfInside" in cat will not show up. I also tried
[_bakgrunnsbilde katt]...
but with the same lack of result, and I believe this is compiled the same way. I am wondering what I am missing here, and hope someone can help. Thanks :)
edit I forgot to add a few lines from my BackGroundPicture.m. It is a method run on start from the ViewDidLoad in ViewController. It is like this in BackGroundPicture.m:
- (void)createObjects {
Cat * katt = [[Cat alloc] init];
}
it is called from ViewController.m like so:
- (void)viewDidLoad
{
[_bakgrunnsbilde createObjects];
}
I know that this get executed. I hope this edit makes sense, my head is ruined after a long day :) Going to check back tomorrow morning.
It will work, but BackGroundPicture.m needs to allocate a cat first.
So in BackGroundPicture.m, do this:
- (id)init {
self = [super init];
if (self) {
_katt = [[Cat alloc] init];
}
return self;
}
In general, remember to allocate objects before you use them. You may also need to create a BackGroundPicture, too as Valentin points out. In viewDidLoad, do this:
bakgrunnsbilde = [[BackGroundPicture alloc] init];
As far as I can see you're accessing the method correctly. You could use the property, for readability sake (you also don't need the cast)
[self.bakgrunnsbilde.katt checkIfTouchHit:touchLocation.x :touchLocation.y]
, but your way of doing it should work as well.
You should check if your -viewDidLoad method gets called and if self.bakgrunnsbilde or self.bakgrunnsbilde.katt is not nil when -viewDidLoad gets called. One of this should get you on the right track.
I want to created and populate an Array in a class and then use the content in the array in the main program... As an example I'll use a list of names of the US States...
This is an update on the original question that is halfway resolved and has been contented for clarity so you can see the code properly.
ArrayStates.h
#import <Foundation/Foundation.h>
#interface ArrayStates : NSObject
#end
ArrayStates.m
#import "ArrayStates.h"
#interface ArrayStates() { NSMutableArray *listOfStates; }
#implementation ArrayStates
- (void)viewDidLoad {
//---initialize the array---
listOfStates = [[NSMutableArray alloc] init];
//---add items---
[listOfStates addObject:#"ALABAMA"];
[listOfStates addObject:#"WYOMING"];
[super viewDidLoad];
}
#end
This is updated code from the previous Question but it still generates a Missing end error on the implementation line, the void wants a . after method prototype and you still can't reference the object in the main program.
I believe altering the ordering if the interface and implementation differentiates whether the array can be accessed within or outside the class (thanks to iHungry for that).
Create a property like Mundi said in the .h, and then just import the ArrayStates.h where ever you need to access the array. You can then make an instance of class ArrayStates, (create an object and alloc-init), and then use that object to access its listOfStates property.
// in ArrayStates.h
#interface ArrayStates : NSObject
#property NSMutableArray *listOfStates;
#end
// in ArrayStates.m
#implementation ArrayStates
#synthesize listOfStates;
//...
-(void)viewDidLoad {
[super viewDidLoad];
listOfStates = [[NSMutableArray alloc] init];
}
#end
// in some other class
ArrayStates *states = [[ArrayStates alloc] init];
NSLog(#"%#", states.listOfStates);
In the viewDidLoad method, you must call super first.
By the way, your ArrayStates class is a subclass of NSObject so its method viewDidLoad will not gonna be called!
I got SO questions also same as this and I tried with solution but still its not working for mine so asked this again.
This is my VCWithProtocol.h
#protocol mydemoDelegate
#optional
-(void)demoDelegateMethodWithSuccess:(BOOL)yesOrNo;
#end
#interface VCWithProtocol : UIViewController
{
id<mydemoDelegate>mydelegate;
}
#property (nonatomic,assign)id<mydemoDelegate>mydelegate;
VCWithProtocol.m
`#synthesize mydelegate`
This is my class where I am trying to use my Delegate
#class VCWithProtocol;
#interface VCTOUseDelegate : UIViewController <mydemoDelegate> //here is where it shows error with cannot find protocol declaration
VCTOUseDelegate.m
VCWithProtocol *obj = [[VCWithProtocol alloc] init];
obj.mydelegate = self;
I tried with Importing VCWithProtocol but not working as well
Instead of #class VCWithProtocol; write #import VCWithProtocol.h
And some good practice Use capital letter for first character of any class name and protocol.
e.g. MyDemoDelegate and avoid retaining delegate use
#property (nonatomic,assign)id<mydemoDelegate>mydelegate;
Synthesize your mydelegate, and call
[self mydelegate];
You need to add #import "VCWithProtocol.h" to the top of your .m file.
#property (nonatomic,**weak**)id<mydemoDelegate>mydelegate;
delegate always needs weak link
I have too much code to know which i need to quote here, but in my app delegate I have an NSMutableArray. Then in another class, it creates a new entry to the NSMutableArray but upon passing back to another class which should use that to display something on screen, it doesn't display anything. Putting an NSLog for the NSMutableArray count at the end of the class creating it displays the number 1, and then putting the same NSLog code at the start of the class which is meant to use that returns 0.
Any ideas why this is?
EDIT: Ok, i'll try and include all related code..
app delegate.h:
#interface palettesAppDelegate : NSObject <UIApplicationDelegate> {
NSMutableArray *colourPalettesContainer;
}
#property (assign, readwrite) NSMutableArray *colourPalettesContainer;
#end
app delegate.m:
#import "palettesAppDelegate.h"
#implementation palettesAppDelegate
#synthesize colourPalettesContainer;
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
Homeview.h:
#import <UIKit/UIKit.h>
#import "HandlingPalettes.h"
#interface HomeView : UIViewController {
HandlingPalettes *handlingPalettes;
}
#end
Homeview.m:
#import "HomeView.h"
#import <QuartzCore/QuartzCore.h>
#implementation HomeView
- (void)viewDidLoad {
[super viewDidLoad];
handlingPalettes = [[HandlingPalettes alloc] init];
[handlingPalettes newPalette];
}
-(void)viewWillAppear:(BOOL)animated {
NSLog(#"view will appear: %i", [dataCenter.colourPalettesContainer count]);
int numberOfExisting = [dataCenter.colourPalettesContainer count];
}
- (void)dealloc {
[handlingPalettes release];
[super dealloc];
}
#end
HandlingPalettes.h:
#import <UIKit/UIKit.h>
#interface HandlingPalettes : UIViewController {
}
-(void)newPalette;
#end
HandlingPalettes.m:
#import "HandlingPalettes.h"
#import "HomeView.h"
#import "palettesAppDelegate.h"
#implementation HandlingPalettes
-(void)newPalette {
palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];
//If this is the first palette
if (dataCenter.colourPalettesContainer == nil) {
dataCenter.colourPalettesContainer = [[NSMutableArray alloc] init];
}
//Add a new palette
[dataCenter.colourPalettesContainer addObject:#"Test1", #"Test2", nil];
NSLog(#"Handling: %i", [dataCenter.colourPalettesContainer count]);
}- (void)dealloc {
[super dealloc];
}
#end
Your main mutablearray is in your app delegate. So, see what happens if in EVERY METHOD that you want to access the array you have the line to set up the app delegate relationship
palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];
Now, when you call the dataCenter object you will be referencing the App Delegate and your program will find the array.
You may also find that you will need to have an #import "palettesAppDelegate.h" in each object that is going to reference the App Delegate.
Note, just adding the app delegate code is not necessarily the proper way to deal with this issue from an architectural standpoint. But if it works you at least know the answer to your original question.
I suspect the problem is ultimately related to confused memory management of the colourPalettesContainer member. You release it in the app delegate's dealloc method, but that class never retains it! It would be much cleaner if you'd follow Apple's memory management guidelines: your classes should only release objects that they own (i.e., that they themselves retained earlier). For example, you can do this by declaring the array's property retain:
#property (retain) NSMutableArray *colourPalettesContainer;
(To prevent leaking the array, you'll also need to release or autorelease it in the newPalette method. Retain and release should always come in close pairs.)
But even better, why not simply create the array in the app delegate's init method, or in its accessor (if for some reason you want to continue creating it only on its first use)? Unless you want to replace all palettes at once, there is no reason to let the array be assigned to from outside the app delegate.
#interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
#private
NSMutableArray *colourPalettesContainer;
}
#property (readonly) NSMutableArray *colourPalettesContainer;
#end
#implementation PalettesAppDelegate
- (NSMutableArray *)colourPalettesContainer {
if (colourPalettesContainer == nil) {
colourPalettesContainer = [[NSMutableArray alloc] init];
return colourPalettesContainer;
}
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
To make the design even cleaner, change the type of the colourPalettesContainer property to NSArray * and add an -addPalette: method to the app delegate. (It is rarely a good idea to publicly expose a mutable array inside a class.) You can then simply get rid of -newPalette in HandlingPalettes. (If you want to have all your palette-handling methods in HandlingPalettes, then simply move the array there. If you need to access the palettes from random places in your app, then you can simply put a retained reference to your HandlingPalettes object in the app delegate.)
Once you clean up the object ownership mess, the count mismatch will either resolve itself "by magic" or the cause will likely become much more obvious. In the latter case, check that the HomeView's dataCenter is actually the same object as the one in HandlingPalettes. (You omitted how HomeView gets its reference — are you sure you aren't creating another instance of the app delegate by accident?)
(By the way, you probably meant to use -addObjects:, not -addObject: in newPalette. Note also that all class names should be capitalized, with no exceptions: i.e., always use PalettesAppDelegate, never palettesAppDelegate. If for some reason Xcode's project template created it like that, simply rename the class. Lowercase class names are much too easy to confuse with variable names. Also, try to find better names in general: e.g., instead of HandlingPalettes, I'd use PalettesViewController (to reflect the fact that it is a subclass of UIViewController); and instead of dataCenter, I'd rather just choose appDelegate.)
I would be inclined to get rid of the newPalette method, and instead create a getter method for colourPalettesContainer in your app delegate.
ie:
appdelegate.h
#interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
NSMutableArray *colourPalettesContainer;
}
#property (non-atomic, retain) NSMutableArray *colourPalettesContainer;
#end
#implementation palettesAppDelegate
appdelegate.m
#import "appdelegate.h"
#synthesize colourPalettesContainer;
- (NSMutableArray *) colourPalettesContainer{
if(colourPalettesContainer==nil){
colourPalettesContainer=[[NSMutableArray alloc] init];
}
return colourPalettesContainer;
}
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
you should then be able to add items by calling
[appDelegate.colourPalettesContainer addObject:object];
I just resolved a cyclic dependency problem by using class forwarding. Now, I am getting a warning of no 'showSumDetails' method found. I don't understand why it should happen at all, any help will be appreciated. Including a bit of code here:
MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
//#import "MyMapViewController.h" obviously this wasn't possible :-(
#class MyMapViewController;
#interface MyAnnotation : NSObject<MKAnnotation> {
MyMapViewController* mapController;
}
MyMapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <MapKit/MKReverseGeocoder.h>
#import "MyAnnotation.h"
#interface MyMapViewController : UIViewController <MKMapViewDelegate>{
MyAnnotation *annot;
}
MyMapViewController.m - where the method actually exists, and it is defined in the header file as well.
#implementation MyMapViewController
#synthesize annot;
-(void) showSumDetails:(id)aSumData{
NSLog(#"mapViewController-showSumDetails");
SumDetailsViewController *wrController = [[SumDetailsViewController alloc] init];
wrController.sumData = aSumData;
[self.navigationController pushViewController:wrController animated:YES];//This needs to be pushed
[wrController release];
}
#end
But the following method in MyAnnotation.m can't find the method above :-(
#implementation MyAnnotation
#synthesize sumData;
#synthesize mapController;
- (void) showPD{//is also defined in header file
NSLog(#"sPD - MyAnn");
[mapController showSumDetails:sumData]; //This doesn't have a clue about showSumDetails method- Why??
}
I'd be glad to provide any more info. Please help!!!
Did you import MyMapViewController.h in MyAnnotation.m?
Since you're using a forward reference for MyMapViewController in MyAnnotation.h you need to import MyMapViewController.h in MyAnnotation.m.