Category header imports not working - objective-c

I have a workspace that has two projects in it. The first project was essentially a test and develop project where I got things working before worrying about tying everything together for real. The second project is bringing all my individually developed view controllers together in a storyboard.
On one of the view controllers I have a bunch of swipe gestures with quite a bit of UIView animation calls nicely formatted for readability and therefore taking a lot of space. I elected to move them out as a category.
The problem is that the compiler is not seeing the instance variable declarations in the main header file.
What has me pulling my hair out is that I did this in the first project and it all worked fine. So I'm carefully comparing the contents of my second project to the first and I see no differences.
Here're some file snippets to help demonstrate how/where I'm defining things, and then snippets of code in the category file that is attempting to access them:
GSBViewController.h
#interface GSBViewController : UIViewController
#property (strong, nonatomic) IBOutlet UISegmentedControl *roundPicker;
#property (strong, nonatomic) IBOutlet UIView *roundsSectionView;
GSBViewController.m
#import "GSBViewController+Swipe.h"
#interface GSBGameBuilderViewController ()
{
UIBarButtonItem *rightGatherBarButton;
NSInteger previousRound;
}
#end
#implementation GSBViewController
#synthesize roundPicker;
#synthesize roundsSectionView;
GSBViewController+Swipe.h
#import "GSBViewController.h"
#interface GSBViewController (Swipe)
- (void)establishSwipeGestures;
#end
GSBViewController+Swipe.m
#import "GSBViewController+Swipe.h"
#implementation GSBViewController (Swipe)
- (void)establishSwipeGestures
{
UISwipeGestureRecognizer *swipeLeft =
[[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:#selector(roundsSectionLeft:)];
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[swipeLeft setNumberOfTouchesRequired:1];
[roundsSectionView addGestureRecognizer:swipeLeft];
// bunch-o-code snipped -- for the time being it's actually all commented out
// as a test and because the LLVM compiler was giving up after too many errors
// and I wanted to see if there was more it would like to tell me about this first --
// and very representative -- problem.
}
#end
The complaint from the compiler is "Use of undeclared identifier 'roundsSectionView'"
If I option-click on the use of roundsSectionView in that line of code where I'm adding the gesture recognizer to it the pop-up correctly describes it as declared in GSBViewController.h
So I'm stumped.
Is there something I can do in Xcode (4.3.2 at the time of this posting :-) to let me see what the included files are? Or is there something non-file-based that is needed to tie a category into the class it's augmenting? I don't remember anything like that being necessary before. In fact, the way I generated the files for this category was through Xcode's File -> New File... Objective-C Category template. Then I just copied the contents of the old ...+Swipe.h and ...+Swipe.m files and pasted them into their respective files in the new project.

A synthesized ivar is private. The compiler won't allow you to access it anywhere execept in the #implementation block where it's created. Neither categories nor subclasses can access the ivar directly; they must use the property: [self roundsSectionView].
There's a slight possibilty that earlier Clangs didn't make synthesized ivars private. Either that or you weren't really doing exactly the same thing in the earlier project.

What #Jacques Cousteau says is correct.
Since you just defined a property and no backing ivar, the category won't be able to access it. If you use self.roundsSectionView it will use the getter method generated for the property and hence it will work.
Or you could define a backing variable in your interface
#interface GSBViewController : UIViewController
{
UIBarButtonItem *roundsSectionView;
}
In this case the categories will be able to access the variable. But not any other class.

Related

Using a button to create a custom class instance and show it in an NSTableView

Im stuck on this problem and it's driving me crazy. What I am attempting to do is have a button click create an instance of a custom class, set it's variables, add it to an NSMutableArray, and display it in a table view. So far it seems that I have everything working except having the info display in the table view.
My custom class TradePaperback just has three NSString properties: title, volume, and publisher.
Here is the code for my header and implementation files:
Header:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (nonatomic, strong) NSMutableArray *tradeArray;
#property (weak) IBOutlet NSTableView *tableView;
- (IBAction)addTrade:(id)sender;
#end
implementation file:
#import "AppDelegate.h"
#import "tradePaperback.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
-(NSMutableArray *)tradeArray{
if (!_tradeArray){
_tradeArray = [[NSMutableArray alloc]init];
TradePaperback *avengers = [[TradePaperback alloc]init];
avengers.title = #"Avengers";
avengers.volume= #"volume 01";
avengers.publisher = #"Marvel Comics";
[_tradeArray addObject:avengers];}
return _tradeArray;}
- (IBAction)addTrade:(id)sender {
TradePaperback *newTrade = [[TradePaperback alloc]init];
newTrade.title = #"New Trade";
newTrade.volume = #"Volume Number";
newTrade.publisher = #"publisher";
[_tradeArray addObject:newTrade];
NSLog(#"added");
NSLog(#"number of items in array is %ld", _tradeArray.count);
[_tableView reloadData];}
#end
My table view is hooked up using bindings. It seems that everything is hooked up correctly since the avengers instance of TadePaperback that i put in shows up when I run the program. As I click the add button I can see from the log in the console that the array is having items added to it, but they just won't display.
Why would the tableView show the first item in the array, but none of the rest?
Here is a picture of the program after running and clicking the add button a couple of times.
program running
I would greatly appreciate any help or advice you guys could give. Thanks in advance.
-Jack
If you're using bindings to populate a table view, you're almost certainly using an NSArrayController to manage the table's content. If you want to add an object to the array controlled by this controller (your tradeArray object), you should do so indirectly: add to the array controller, which will in turn update your array. NSArrayController provides a number of add... or insert.. methods; decide which one suits you best, and use it to replace your call to [_tradeArray addObject:...].
The reason this approach works, and yours doesn't is because this engages the key-value coding/observing machinery that underpins bindings. Your approach essentially adds the object behind the array controller's back - it's not KVO/KVC-compliant, so the array controller remains unaware of the change. Cocoa does provide you with a way of editing the original array in a KVO/KVC-friendly manner if you so wish, it's just a little more work: try the code below, then read Apple's NSKeyValueCoding Protocol Reference and their Key-Value Coding Programming Guide for an explanation:
// Instead of [_tradeArray addObject:newTrade];
[[self mutableArrayValueForKey:#"_tradeArray"] addObject:newTrade];

How to declare a variable from user input?

I am fairly new to programming and am working with Objective-C in Xcode 5.
I'm presently making an OSX application in Xcode that uses Cramer's Rule (this matrix math method to calculate the intersecting point of three lines).
I really need some help with this one concept- I need to be able to take the user's input from multiple text boxes (assign them all a variable), put them through cramer's rule, and feed the answer out through a label.
I've made the storyboard and assigned one of the 12 text boxes (to test it) as an outlet and the label as an outlet and a button as an action, and tried a few different ways to just take the user input and (unaltered) feed it back out through the label so I know what I'm working with before I get into the math, and it's been unsuccessful. Having major syntax problems.
I have attached my code below:
//
// NewClass.h
// Cramer's Rule
#import <Foundation/Foundation.h>
#interface NewClass : NSViewController <NSTextFieldDelegate> {
IBOutlet NSTextField *box_a;
IBOutlet NSTextField *coord;
NSString *string;
}
#property (nonatomic, retain) IBOutlet NSTextField *box_a;
#property (nonatomic, retain) IBOutlet NSTextField *coord;
- (IBAction)calculate:(id)sender;
#end
AND
//
// NewClass.m
// Cramer's Rule
#import "NewClass.h"
#implementation NewClass
#synthesize box_a;
#synthesize coord;
- (IBAction)calculate:(id)sender {
NSTextField * input=box_a;
coord =input;
}
#end
As far as I know, I have the most up to date version of Xcode, and there is no option for creating a storyboard for an OSX project. Storyboards are for iOS projects. And that would explain the reason why you're unable to hook any thing up from the storyboard to your code.
This isn't to say that a storyboard can't be put in an OSX project--it can't. But it can't be selected from the Cocoa section of new files to create--only the Cocoa Touch section, which is iOS stuff--not OSX.
You have to use NSTextFieldDelegate, it have callback methods like in iOS:
- (void)textDidBeginEditing:(NSNotification *)notification;
- (void)textDidEndEditing:(NSNotification *)notification;
- (void)textDidChange:(NSNotification *)notification;
- (BOOL)acceptsFirstResponder;
For example:
- (void)textDidChange:(NSNotification *)notification{
if ([notification object]== box_a)
{
// ...
}else if ([notification object]== box_b)
{
// ...
}
}
Your problem is more fundamental than syntactical, you need to go and study up on what various things are and how they behave, this includes: variables, properties, objects and object references.
To briefly introduce why you're going wrong: Think of an object as a building. What is "in" the building may change over time, but the address of the building (usually!) does not. An address refers you to a building, and that is what an object reference does.
A variable is a box which holds a value of some type, that value can change over time, but the box does not.
When you declare:
NSTextField *input;
You are requesting that a variable be created for you which can hold references to objects - it does not hold an object anymore than address is a building, it just tells you where to find an object.
When you then assign a value to your variable:
NSTextField *input = box_a;
You are requesting the the value in box_a be copied and placed (stored) in input. That value is an object reference, it is not an object. Whatever object was referenced by box_a is not altered in anyway by this statement - what is in the house doesn't change, you just write the house's address down somewhere else.
When you then do:
coord = input;
you are doing the same thing - copying addresses. No objects are altered. The objects you are referring to are of type NSTextField, they have a visual representation on the screen, copying their addresses doesn't alter that visual representation anymore than copying the address of a building changes what is in the building.
When it comes to properties your code suggests a confusion between a property, which is a piece of code which does something, and its backing variable, a variable which that piece of code operates on.
Understanding these concepts is vital. You need to go an study up some more on programming.
HTH

Split Objective-C Code into multiple files

I often feel the need to split the Objective-C code into multiple files for better readability. I want to avoid making classes and call them. I want simple import (like in php).
If someone could please refer a working example.
I think you're looking at categories in this case:
All you have to do is to create a new .h .m pair and in the .h file:
#import MyClass.h
#interface MyClass(Networking)
//method declarations here
#end
and in the .m file:
#import MyClass+Networking.h
#implementation MyClass(Networking)
//method definitions here
#end
And in MyClass.m file - do #import MyClass+Networking.h and you're all set. This way you can extend your class.
You say “I want to avoid making classes and call them.” You need to overcome your fear of adding classes. If you feel the need to split a class's implementation into multiple files, chances are you are trying to do too much in a single class. You need to let that class hand off (“delegate”) some responsibilities to other classes.
That said, there are a couple of ways you can split up a class's implementation. The better way, short of fixing your bloated class design, is to use categories or class extensions. You can read all about categories and extensions in The Objective-C Programming Language. Note that the linker will merge the categories and extensions into the class when it creates your executable file, so there's no runtime penalty for using categories or extensions on your own classes.
The worse way is to use the C preprocessor's #include directive to paste multiple files together. You can just take some methods out of the implementation file and stick them in new “fragment” file, then #include the fragment file in the implementation file. Doing this will make it harder to understand your source code. I would not recommend doing this, but here's an example anyway:
MyObject.m
#import "MyObject.h"
#implementation MyObject
- (void)aMethod { ... }
#include "MyObject-moreMethods.m"
#end
MyObject-moreMethods.m
// Note: do not include this target in the “Compile Sources” build phase of your target.
// And **NO** #implementation statement here!
- (void)methodTwo { ... }
- (void)methodThree { ... }
[EDIT/UPDATE -- I have abandoned the approach described below in favor of using categories, as mentioned in some of the other answers. My typical situation is that as a view has control components added, the View Controller file becomes unwieldy as code is added to accommodate the various delegate and data source methods for the controls. Now I add in code stubs in the view controller file, then implement them for real in a class category. For instance, I might have an AlbumViewController screen that has a search bar and a collection view, so I create categories AlbumViewController+SearchBar and AlbumViewController+CollectionView. This allows the View Controller class to stay at a reasonable size, without incurring any of the drawbacks I listed below for included files. The only downside is that any instance variables, ie properties, must be declared publicly for a category to access them.]
I also want to split my files up, but think categories are not the correct solution in some cases. For example, as nibs grow to include multiple objects (such as tables, buttons, nav bars, tabs, etc) the need for placing all the supporting methods in the viewcontroller.m file can lead to a very large and unwieldy file.
For this discussion, I am going to refer to the original/standard .m file as the parent, and the subsidiary .m files as children.
The goal is to have a single parent .h and .m, and multiple child .m files each of which can be edited independently, but compiled as if all the child .m files were in the parent .m file.
This would be useful if one wants the ability to, for instance, place all table related methods in a file, edit it, and then have it compile as if it were included in the viewcontroller.m implementation file. It seems this is possible, but requires a little effort, and has one (possibly serious) drawback.
The thing to keep in mind is that there are two distinct tools being used: the IDE (which provides intelligent source editing) and the compiler/make system which turns a project's source code into a runnable app.
To get the IDE to work as expected, the child files need to appear to be part of the implementation of the class. This can be accomplished by wrapping the #implementation and #end directives in conditional compilation macros. When editing a file on its own, the IDE considers the child files to be the body of the class, but the compiler doesn't.
To get the compiler to not complain, you can't have the child files considered part of the target -- instead they get pulled in through the preprocessor #include directive. This can be accomplished by not adding them to the target when the file is created (or added to the project), or by removing them on the "Build Phases" -> "Compile Sources" pane.
You then #include the child .m files within the body of the parent .m files. The compiler loads them "in place" and compiles the source as wished for without complaints.
The drawback of this approach (so far) is that the debugger does not recognize the child methods, and will not break on breakpoints put on them. For that reason I suggest that this approach only be used either after the code is thoroughly tested, or for code chunks that are relatively trivial and well-known, such as table delegate and data source methods.
Here are the .h and .m files for a project with a table and a text field in a nib, with the supporting delegate methods defined in child .m files. In the nib, the interface objects are wired up normally, and have the delegates set to the file owner.
File (parent) "MyViewController.h":
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
#property (retain, nonatomic) IBOutlet UITableView *myTable;
#property (retain, nonatomic) IBOutlet UITextField *myTextField;
#end
File (parent) MyViewController.m:
#import "MyViewController.h"
#define VIEW_CONTROLLER_MAIN_BODY 1
#interface MyViewController ()
#end
#implementation MyViewController
#include "MyViewController_TableMethods.m"
#include "MyViewController_TextFieldMethods.m"
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_myTable release];
[_myTextField release];
[super dealloc];
}
File (child) MyViewController_TableMethods.m:
#import <UIKit/UIKit.h>
#import "MyViewController.h"
#ifndef VIEW_CONTROLLER_MAIN_BODY
#implementation ViewController
#endif
#pragma mark -
#pragma mark Table View Common Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
static NSString *myIdentifier = #"myCellIdentifier";
static UITableViewCellStyle myStyle = UITableViewCellStyleSubtitle;
UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:myIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:myStyle reuseIdentifier:myIdentifier] autorelease];
}
cell.textLabel.text = #"Title";
cell.detailTextLabel.text = #"Details";
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
#ifndef VIEW_CONTROLLER_MAIN_BODY
#end
#endif
File (child) MyViewController_TextFieldMethods.m:
#import <UIKit/UIKit.h>
#import "MyViewController.h"
#ifndef VIEW_CONTROLLER_MAIN_BODY
#implementation MyViewController
#endif
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
self.myTextField.text = #"Woo hoo!";
return YES;
}
#ifndef VIEW_CONTROLLER_MAIN_BODY
#end
#endif
This is a good indication that your class is just too large.
One approach: Use categories. Declarations can often stay in the header. Then your implementations may be divided. Just make sure to specify the category you are implementing, so the compiler may match it with its declaration, and inform you when you miss a definition.
A good way to break-down your big class is group functionality in Categories (like Apple does in UIViewController). For a big class, I generally group methods and properties related to their repective functionality and then
In base header file, I split
#interface SomeClass : NSObject
#property (strong, nonatomic) BaseProperty *sp;
- (void)someMethodForBase;
#end
#interface SomeClass (FunctionalityOne)
#property (strong, nonatomic) FuncOne *fpOne;
- (void)someMethodForFunctionalityOne;
#end
#interface SomeClass (FunctionalityTwo)
#property (strong, nonatomic) FuncTwo *fpTwo;
- (void)someMethodForFunctionalityTwo;
#end
Because you can't add property in category (You can't add new iVar and property don't synthesis in category) so you declare it in implementation of base Extension again.
#interface SomeClass()
#property (strong, nonatomic) FuncOne *fpOne;
#property (strong, nonatomic) FuncTwo *fpTwo;
#end
#implementation SomeClass
//base class implementation
- (void)someMethodForBase {
}
#end
Implementing respective functionality in SomeClass+FunctionalityOne.m
#implementation SomeClass (FunctionalityOne)
#dynamic fpOne;
//Functionality one implementation
- (void)someMethodForFunctionalityOne {
}
#end
Implementing respective functionality in SomeClass+FunctionalityTwo.m
#implementation SomeClass (FunctionalityTwo)
#dynamic fpTwo;
//Functionality two implementation
- (void)someMethodForFunctionalityTwo {
}
#end
This way I cleanly organise my big class implementation into small classes and all class functionalities information grouped in single base header for read and import.
its better to use Categories in iOS keep the code clean .
I know this is an old thread and the Objective C gods won't like this solution, but if you need to split files, create a new .m file and paste your code there. Then, #include "yournewfile.m" after #implementation in the .m file where you want to include it. The trick to avoiding a compiler error is to go to the Build Phase and remove "yournewfile.m" from the Compile Sources.

Why can't I access variables when I subclass a customised UIViewController?

I am new to iOS dev and apologies if the answer is obvious...but it isn't to me.
I have an APP with a Navigation controller at its root.
I have many very similar looking areas of the app to be created.
These are each to be UItableviewcontroller which has had a fair bit of customising done to allow buttons and other controls beside the tableview which has been reduced in size to allow for controls beside and below it.
The buttons, text, background etc etc and the data that gets loaded must all be individual to the particular are of the APP.
I created a UItableviewcontroller subclass by simply adding a new file subclass in Xcode.
I created my interface in the xib...created all the methods to drive what I need to in it.
Looks great...all seems fine. If I use it alone...works well.
Problem: I can't figure out how to subclass my custom sub-classed UITVController!
None of its properties are available from inside the new sub-class.
I clearly don't understand how things work here.
I have tried adding a new file > UIViewcontroller sub-class and changing the superclass to my custom superclass...to no avail. No properties accessible.
I have dug and dug and become more confused than anything else.
Is someone kind enough to help me get it right. Frustration is building.
Thanks
Keispe
EDIT:
Whoa found the problem. I have had Xcode open for many many days with several projects open.
It had totally weirded out!
In fact jrturton and eugene...I did know what I was doing (I thought I was going crazy...done this before in my app and suddenly no worky) Xcode had totally lost it's brains!
Anyone seen Xcode do that before??? using 4.1
Bloody hell that wasted a heap of valuable time including yours.
Thanks fellas
When you subclass anything, you can access your parent's class properties by addressing self via dot syntax
#interface BaseClass : NSObject {
#public
NSString *baseclassString;
}
#property (nonatomic, copy) NSString *name;
#end
.h
#interface HigherClass : BaseClass
#end
.m
#implementation HigherClass
- (id)init {
self = [super init];
self.name = #"Hola";
self->baseclassString = #"Hola";
return self;
}
- (void)viewDidLoad {
NSLog(#"name: %#", self.name);
}
#end
This all isn't 100% memory clean but you've gotta get a hang of what is happening here and adjust it properly to your application.

Objective-C header file not recognizing custom object as a type

I'm working on a game for iPad using cocos2d which involves a board filled with different types of tiles. I've created a custom class called Tile as a general template for tiles and a few subclasses of Tile which have different properties and methods. I've also created a class called Board which, among other things, keeps track of the locations of all the tiles using a special coordinate system.
For some reason, in the Board class, the compiler doesn't seem to be recognizing Tile as a type of object, even though I've added #import "Tile.h" at the top of the file.
Here's the relevant code (just ask if there's other parts of the code you want to see):
Tile.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Board.h"
#interface Tile : NSObject
-(void) updateNeighbors;
#property (nonatomic, retain) CCSprite* sprite;
#property (assign) CGPoint coords;
#property (assign) CGPoint positionInPoints;
#property (nonatomic, retain) NSMutableArray *neighbors;
#end
Board.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Tile.h"
#interface Board : NSObject
+(Board*)sharedBoard;
- (void) putTile: (Tile*) tile AtIndex: (CGPoint) index; //<-- error here!
- (void) replaceTileAtIndex: (CGPoint) index1 WithTileAtIndex: (CGPoint) index2;
- (Tile*) tileAtIndex: (CGPoint) index; //<-- error here!
- (void) populate;
#property (nonatomic, retain) NSMutableArray *tiles;
#property (nonatomic, retain) NSString *type;
#property (assign) CGPoint size;
#end
This code will not even build and I'm getting the following error where indicated:
Expected '(' before 'Tile'
If I change the type from (Tile*) to (NSObject*), it fixes the error, which leads me to believe that Tile is not being recognized as a type of object.
I've searched via Google and this site and cannot figure out why this is happening.
Update
Dumb mistake; easy to fix.
As you all have pointed out the problem is that the two header files are importing each other, which is not allowed. For now, I've fixed the problem by moving the #import "Board.h" statement to Tile.m, since it isn't needed in the header file. Later on, if I decide to use Board in the Tile.h file I will use forward referencing (#class Board;), as a few of you suggested.
Thanks again!
This is a classic problem with headers importing headers. You have a circle here: Tile.h is importing Board.h, which imports Tile.h. This confuses the compiler -- it gets stuck in a loop.
You solve this by not importing headers into headers. You still need to let the compiler know about Tile, however. In Board.h, make a "forward declaration" of the class:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#class Tile; // Dear compiler,
// Tile is a class that I will need to refer
// to in this file. Please consider it to be a
// type; I promise it'll be defined at runtime.
// Sincerely, stephenalexbrowne
#interface Board : NSObject
//etc.
This assures the compiler that there is a class called Tile that will exist at runtime; you can then refer to that name in the remainder of your header. In your implementation for Board, you import Tile.h. That will let the compiler see the methods and properties associated with the Tile class where they are needed.
Likewise, move the #import "Board.h" into Tile.m. Since you aren't referring to the Board class in Tile.h, you don't need to make a forward declaration.
In general, it is best to import your class headers only into the implementation files where they are needed. Framework headers, since they will never cause a cycle with your code, can and -- because you need to refer to many of the classes declared in them -- should be imported into your headers.
Two files cannot import each other. You need to move the import directives to the implementation files, and instead just forward-declare the classes in the headers (e.g. #class Tile; in Board.h).
The reason circular imports don't work is because #import literally includes the text from the imported file in-place. But it also ensures that the text from a file will only be included once, in order to avoid duplicate declarations. So when Tile.h says that the text from Board.h needs to go before it, and Board.h says the text from Tile.h needs to go before it, there's literally nothing the compiler can do — one of them needs to go first, and that file is going to complain because it was expecting the other one to already be there.
This may not be the problem, but what happens if you remove the "#import "Board.h"" from the Tile.h file. You might have a problem with circular referencing