iOS blurred text: detecting & solving it once and for all? - objective-c

More than once I've encountered the situation where a UIView (subclass) ends up on a fractional offset, e.g. because its dimensions are odd and it's centered, or because its location is based on the center of an odd-sized container.
This results in blurred text (or images), because iOS will try to render the view (and subviews) on half-pixel offsets. I feel that calling CGRectIntegral() for every frame-change is not a perfect solution.
I'm looking for the best way to detect those situations easily. While writing this question I came up with quite a drastic approach, which revealed more off-by-½'s in my current project than I could imagine.
So this is for sharing. Comments and suggestions for better or less drastic alternatives are more than welcome.
main.m
#import <objc/runtime.h>
#import "UIViewOverride.h"
int main(int argc, char *argv[]) {
#ifdef DEBUGVIEW
Method m1,m2;
IMP imp;
m1 = class_getInstanceMethod([UIView class], #selector(setFrame:));
m2 = class_getInstanceMethod([UIViewOverride class], #selector(setFrameOverride:));
imp = method_getImplementation(m2);
class_addMethod([UIView class], #selector(setFrameOverride:), imp, method_getTypeEncoding(m1));
m2 = class_getInstanceMethod([UIView class], #selector(setFrameOverride:));
method_exchangeImplementations(m1,m2);
m1 = class_getInstanceMethod([UIView class], #selector(setCenter:));
m2 = class_getInstanceMethod([UIViewOverride class], #selector(setCenterOverride:));
imp = method_getImplementation(m2);
class_addMethod([UIView class], #selector(setCenterOverride:), imp, method_getTypeEncoding(m1));
m2 = class_getInstanceMethod([UIView class], #selector(setCenterOverride:));
method_exchangeImplementations(m1,m2);
#endif
// etc
UIViewOverride.m
This is implemented as a UIView subclass, which avoids casts and/or compiler warnings.
#define FRACTIONAL(f) (fabs(f)-floor(fabs(f))>0.01)
#implementation UIViewOverride
#ifdef DEBUGVIEW
-(void)setFrameOverride:(CGRect)newframe
{
if ( FRACTIONAL(newframe.origin.x) || FRACTIONAL(newframe.origin.y) )
{
[self setBackgroundColor:[UIColor redColor]];
[self setAlpha:0.2];
NSLog(#"fractional offset for %#",self);
}
[self setFrameOverride:newframe]; // not a typo
}
-(void)setCenterOverride:(CGPoint)center
{
[self setCenterOverride:center]; // not a typo
if ( FRACTIONAL(self.frame.origin.x) || FRACTIONAL(self.frame.origin.y) )
{
[self setBackgroundColor:[UIColor greenColor]];
[self setAlpha:0.2];
NSLog(#"fractional via center for %#",self);
}
}
#endif
Problematic views will generate log messages and turn up transparent and either red or green.
-DDEBUGVIEW to be set as compiler flag in Debug mode.

You can get this same functionality through the CoreAnimation instrument and its misaligned flag.

Related

Has anyone found **legal** overrides to customize drawing of NSTabView?

BGHUDAppKit BGHUDTabView _drawThemeTab private API override now broken
For years, I have been using code originally based off of BGHUDAppKit, and found replacements for all of the private API that BGHUDAppKit overrides.
Except for one that I could not find a way to replace...
-[NSTabView _drawThemeTab:withState:inRect:]
(Note: I also use venerable PSMTabBarControl in many circumstances, so if all else fails I'll convert all my tab views to PSMTabBarControl)
Apple has now added the dark NSAppearance in 10.14 Mojave (so in ~10 years I can use it once we stop supporting High Sierra).
Whichever selfish dev at Apple writes NSTabView does not believe in making his view customizable, unlike all of the other NSControls which are customizable.
Here is part of the hackish overrides for custom drawing of NSTabView:
// until we can eliminate private API _drawThemeTab:, return nil for new NSAppearance
- (id) appearance { return nil; }
- (id) effectiveAppearance { return nil; }
-(void)_drawThemeTab:(id) tabItem withState:(NSUInteger) state inRect:(NSRect) aRect {
NSInteger idx = [self indexOfTabViewItem: tabItem];
int gradientAngle = 90;
NSBezierPath *path = nil;
aRect = NSInsetRect(aRect, 0.5f, 0.5f);
if([self tabViewType] == NSLeftTabsBezelBorder) {
gradientAngle = 0;
} else if([self tabViewType] == NSRightTabsBezelBorder) {
gradientAngle = 180;
}
NSColor *specialFillColor = [tabItem color];
NSColor *outlineColor = nil;
NSString *name = [specialFillColor description];
// MEC - added new prefix 12/15/17 to fix white border around last segment in High Sierra
if ( [name hasPrefix:#"NSNamedColorSpace System"] || [name hasPrefix:#"Catalog color: System controlColor"])
specialFillColor = nil;
else if ( [name isEqualToString: #"NSCalibratedWhiteColorSpace 0 1"] )
[specialFillColor set];
else
{
outlineColor = specialFillColor;
specialFillColor = nil;
}
... etc ...
It's probably preferrable to completely disable NSTabView's drawing (setting its tabViewType to NSNoTabsNoBorder), and create a custom segmented bar view to draw the selection separately (as a sibling view). This allows you to completely control the appearance, layout, and sizing of that custom implementation rather than relying on any details of NSTabView.
Looking at the view hierarchy of an NSTabViewController, you can see that it has this same approach by using an NSSegmentedControl as a separate subview managing selection from the NSTabView.

unrecognized selector sent to class when trying to create UIColor

I'm trying to create a custom color out of a hex color code. I have a seperate class called UIColor+Hex, that takes in a hex string and converts it to a color code and returs a UIColor.
UIColor+Hex.h
#import <UIKit/UIKit.h>
#interface UIColor (Hex)
+ (UIColor *)colorWithHexString:(NSString *)hex;
#end
UIColor+Hex.m
#import "UIColor+Hex.h"
#implementation UIColor (Hex)
+ (UIColor *)colorWithHexString:(NSString *)hex
{
if ([hex length]!=6 && [hex length]!=3)
{
return nil;
}
NSUInteger digits = [hex length]/3;
CGFloat maxValue = (digits==1)?15.0:255.0;
NSUInteger redHex = 0;
NSUInteger greenHex = 0;
NSUInteger blueHex = 0;
sscanf([[hex substringWithRange:NSMakeRange(0, digits)] UTF8String], "%x", &redHex);
sscanf([[hex substringWithRange:NSMakeRange(digits, digits)] UTF8String], "%x", &greenHex);
sscanf([[hex substringWithRange:NSMakeRange(2*digits, digits)] UTF8String], "%x", &blueHex);
CGFloat red = redHex/maxValue;
CGFloat green = greenHex/maxValue;
CGFloat blue = blueHex/maxValue;
return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
}
#end
I then have UIColor+Hex.h imported to one of my other classes and make a call to it by:
[self setSelectedfillColor:[UIColor colorWithHexString:#"FF0000"].CGColor];
Whenever I hit this code I get this error...
'NSInvalidArgumentException', reason: '+[UIColor colorWithHexString:]: unrecognized selector sent to class 0x873d60'
I've tried everything I could think of but I still keep getting that error. Anyone have any ideas why this would be happening?
Add -ObjC -all_load to your Other Linker Flags in your project under the Build Settings.
-ObjC allow the static library to use objective-c specific stuffs like kvc or categories.
-all_load solve a bug in gcc/llvm, where -ObjC is not correctly used.
https://developer.apple.com/library/mac/#qa/qa2006/qa1490.html
Make sure to add UIColor+Hex.m to the Compile Sources list in the Build Phases tab.
The compiler doesn't complain during the build but dies on the selector at runtime.
All too often, it's the missing classes in "Compile Sources" in XCode.
Tested your category as you posted and it works fine even with the cgcolor property method. Separate those two lines and make sure the problem is not with setSelectedFillColor. Sometimes the debug errors can be misleading.

Updating NSView asynchronously from a thread

First of all, I'm an Objective-C novice. So I'm not very familiar with OS X or iOS development. My experience is mostly in Java.
I'm creating an agent-based modeling-framework. I'd like to display the simulations and to do that I'm writing a little application. First, a little bit about the framework. The framework has a World class, in which there is a start method, which iterates over all agents and has them perform their tasks. At the end of one "step" of the world (i.e., after all the agents have done their thing), the start method calls the intercept method of an object that implements InterceptorProtocol. This object was previously passed in via the constructor. Using the interceptor, anyone can get a hook into the state of the world. This is useful for logging, or in the scenario that I'm trying to accomplish: displaying the information in a graphical manner. The call to intercept is synchronous.
Now as far as the GUI app is concerned, it is pretty simple. I have a controller that initializes a custom view. This custom view also implements InterceptorProtocol so that it can listen in, to what happens in the world. I create a World object and pass in the view as an interceptor. The view maintains a reference to the world through a private property and so once I have initialized the world, I set the view's world property to the world I have just created (I realize that this creates a cycle, but I need a reference to the world in the drawRect method of the view and the only way I can have it is if I maintain a reference to it from the class).
Since the world's start method is synchronous, I don't start the world up immediately. In the drawRect method I check to see if the world is running. If it is not, I start it up in a background thread. If it is, I examine the world and display all the graphics that I need to.
In the intercept method (which gets called from start running on the background thread), I set setNeedsToDisplay to YES. Since the start method of the world is running in a separate thread, I also have a lock object that I use to synchronize so that I'm not working on the World object while it's being mutated (this part is kind of janky and it's probably not working the way I expect it to - there are more than a few rough spots and I'm simply trying to get a little bit working; I plan to clean up later).
My problem is that the view renders some stuff, and then it pretty much locks up. I can see that the NSLog statements are being called and so the code is running, but nothing is getting updated on the view.
Here's some of the pertinent code:
MasterViewController
#import "MasterViewController.h"
#import "World.h"
#import "InfectableBug.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_worldView = [[WorldView alloc] init];
World* world = [[World alloc] initWithName: #"Bhumi"
rows: 100
columns: 100
iterations: 2000
snapshotInterval: 1
interceptor: _worldView];
for(int i = 0; i < 999; i++) {
NSMutableString* name = [NSMutableString stringWithString: #"HealthyBug"];
[name appendString: [[NSNumber numberWithInt: i] stringValue]];
[world addBug: [[InfectableBug alloc] initWithWorld: world
name: name
layer: #"FirstLayer"
infected: NO
infectionRadius: 1
incubationPeriod: 10
infectionStartIteration: 0]];
}
NSLog(#"Added all bugs. Going to add infected");
[world addBug: [[InfectableBug alloc] initWithWorld: world
name: #"InfectedBug"
layer: #"FirstLayer"
infected: YES
infectionRadius: 1
incubationPeriod: 10
infectionStartIteration: 0]];
[_worldView setWorld: world];
//[world start];
}
return self;
}
- (NSView*) view {
return self.worldView;
}
#end
WorldView
#import "WorldView.h"
#import "World.h"
#import "InfectableBug.h"
#implementation WorldView
#synthesize world;
- (id) initWithFrame:(NSRect) frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void) drawRect:(NSRect) dirtyRect {
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
CGContextClearRect(myContext, CGRectMake(0, 0, 1024, 768));
NSUInteger rows = [world rows];
NSUInteger columns = [world columns];
NSUInteger cellWidth = 1024 / columns;
NSUInteger cellHeight = 768 / rows;
if([world running]) {
#synchronized (_lock) {
//Ideally we would need layers, but for now let's just get this to display
NSArray* bugs = [world bugs];
NSEnumerator* enumerator = [bugs objectEnumerator];
InfectableBug* bug;
while ((bug = [enumerator nextObject])) {
if([bug infected] == YES) {
CGContextSetRGBFillColor(myContext, 128, 0, 0, 1);
} else {
CGContextSetRGBFillColor(myContext, 0, 0, 128, 1);
}
NSLog(#"Drawing bug %# at %lu, %lu with width %lu and height %lu", [bug name], [bug x] * cellWidth, [bug y] * cellHeight, cellWidth, cellHeight);
CGContextFillRect(myContext, CGRectMake([bug x] * cellWidth, [bug y] * cellHeight, cellWidth, cellHeight));
}
}
} else {
[world performSelectorInBackground: #selector(start) withObject: nil];
}
}
- (BOOL) isFlipped {
return YES;
}
- (void) intercept: (World *) aWorld {
struct timespec time;
time.tv_sec = 0;
time.tv_nsec = 500000000L;
//nanosleep(&time, NULL);
#synchronized (_lock) {
[self setNeedsDisplay: YES];
}
}
#end
start method in World.m:
- (void) start {
running = YES;
while(currentIteration < iterations) {
#autoreleasepool {
[bugs shuffle];
NSEnumerator* bugEnumerator = [bugs objectEnumerator];
Bug* bug;
while((bug = [bugEnumerator nextObject])) {
NSString* originalLayer = [bug layer];
NSUInteger originalX = [bug x];
NSUInteger originalY = [bug y];
//NSLog(#"Bug %# is going to act and location %i:%i is %#", [bug name], [bug x], [bug y], [self isOccupied: [bug layer] x: [bug x] y: [bug y]] ? #"occupied" : #"not occupied");
[bug act];
//NSLog(#"Bug has acted");
if(![originalLayer isEqualToString: [bug layer]] || originalX != [bug x] || originalY != [bug y]) {
//NSLog(#"Bug has moved");
[self moveBugFrom: originalLayer atX: originalX atY: originalY toLayer: [bug layer] atX: [bug x] atY: [bug y]];
//NSLog(#"Updated bug position");
}
}
if(currentIteration % snapshotInterval == 0) {
[interceptor intercept: self];
}
currentIteration++;
}
}
//NSLog(#"Done.");
}
Please let me know if you'd like to see any other code. I realize that the code is not pretty; I was just trying to get stuff to work and I plan on cleaning it up later. Also, if I'm violating an Objective-C best practices, please let me know!
Stepping out for a bit; sorry if I don't respond immediately!
Whew, quiet a question for probably a simple answer: ;)
UI updates have to be performed on the main thread
If I read your code correctly, you call the start method on a background thread. The start method contains stuff like moveBugFrom:... and also the intercept: method. The intercept method thus calls setNeedsDisplay: on a background thread.
Have all UI related stuff perform on the main thread. Your best bet is to use Grand Central Dispatch, unless you need to support iOS < 4 or OS X < 10.6 (or was it 10.7?), like this:
dispatch_async(dispatch_get_main_queue(), ^{
// perform UI updates
});

My factory method isn't working as intended

I'm making a game, which uses large pixel art for graphics. As I would have to declare sprite.scale = 2; and [sprite.texture setAliasTexParameters]; for each and every sprite, I decided to make a factory method. I got it workin, but for some reason it crashes the program at some situations.
This is my factory code in .m file:
#implementation pixelSprite
+ (id) spriteFromFrame:(NSString *)frame setScale:(BOOL)scale resetAnchor:(BOOL)reset {
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:frame];
[sprite.texture setAliasTexParameters];
if (scale) {sprite.scale = 2;}
if (reset) {sprite.anchorPoint = ccp(0, 0);}
return sprite;
}
#end
And this from .h file:
#interface pixelSprite : CCSprite {}
+ (id)spriteFromFrame:(NSString*)frame setScale:(BOOL)scale resetAnchor:(BOOL)reset;
#end
I made button sprites with it like this and it works flawlessly.
CCSprite *spriteCampaign1 = [pixelSprite spriteFromFrame:#"buttonCampaign1.png" setScale:FALSE resetAnchor:FALSE];
For some reason this for example will crash the program:
CCSprite *bg3 = [pixelSprite spriteFromFrame:#"bgMenu3.png" setScale:TRUE resetAnchor:FALSE];
//bg3.anchorPoint = ccp(0.5, 0);
bg3.position = ccp(240, 210);
[self addChild:bg3 z:1];
I did include the .h file in those .m files I wanted to use the sprite factory.
Verify that the spriteFrameCache contains an entry for your failing sprites. If it does not, your factory will return a nil sprite, and the [self addChild:bg3 z:1] will fail on an NSAssert. Returning nil (from your factory) is not a bad thing, but it is expectable behaviour. You should program defensively around it:
CCSprite *bg3 = [pixelSprite spriteFromFrame:#"bgMenu3.png" setScale:TRUE resetAnchor:FALSE];
if(bg3) {
//bg3.anchorPoint = ccp(0.5, 0);
bg3.position = ccp(240, 210);
[self addChild:bg3 z:1];
} else {
CCLOGERROR(#"whatever your flavor of logging is");
}

Xcode seems to not want to include my class

So, I have a class called MazeCell which is declared in "MazeCell.h"
#import <Foundation/Foundation.h>
enum {
MazeCellEdgeWall = 0,
MazeCellEdgeGate = 1,
MazeCellEdgeExit = 2
};
typedef NSUInteger MazeCellEdge;
#interface MazeCell : NSObject {
MazeCellEdge left;
MazeCellEdge right;
MazeCellEdge down;
MazeCellEdge up;
NSUInteger drawCount;
NSUInteger row;
NSUInteger column;
}
#property MazeCellEdge left;
#property MazeCellEdge right;
#property MazeCellEdge down;
#property MazeCellEdge up;
#property NSUInteger drawCount;
#property NSUInteger row;
#property NSUInteger column;
- (id)initWithLeft:(MazeCellEdge)newLeft
right:(MazeCellEdge)newRight
up:(MazeCellEdge)newUp
down:(MazeCellEdge)newDown
row:(NSUInteger)newRow
column:(NSUInteger)newColumn;
#end
Xcode keeps displaying warnings like "warning: 'MazeView' may not respond to '-left'" for all the methods. The funny thing is that the code runs fine on the simulator, it's just that XCode doesn't know the methods.
I was content to ignore the messages until XCode wouldn't let me use MazeCellEdgeWall because it hadn't been declared earlier (all these warnings and errors are in different classes).
So I was wondering if anyone saw any blatant errors that I may have missed because I'm new to programming in general.
Edit: I didn't originally include the code since it is long, but here is the code giving errors.
Here is "MazeCell.m":
#import "MazeCell.h"
#implementation MazeCell
#synthesize left;
#synthesize right;
#synthesize down;
#synthesize up;
#synthesize drawCount;
#synthesize row;
#synthesize column;
-(id) init {
if (self = [super init]) {
right = MazeCellEdgeWall;
up = MazeCellEdgeWall;
left = MazeCellEdgeWall;
down = MazeCellEdgeWall;
drawCount = 0;
}
return self;
}
- (id)initWithLeft:(MazeCellEdge)newLeft
right:(MazeCellEdge)newRight
up:(MazeCellEdge)newUp
down:(MazeCellEdge)newDown
row:(NSUInteger)newRow
column:(NSUInteger)newColumn
{
if (self = [super init]) {
left = newLeft;
right = newRight;
up = newUp;
down = newDown;
drawCount = 0;
row = newRow;
column = newColumn;
}
return self;
}
#end
Here is MazeView.h:
#import "MazeView.h"
#import "MazeCell.h"
#import "NSMutableArray+Stack.h"
#define kCellSidesSize 80.0
#implementation MazeView
#synthesize maze;
#synthesize controller;
#synthesize interfaceOrientation;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
interfaceOrientation = UIInterfaceOrientationPortrait;
[self setBackgroundColor:[UIColor greenColor]];
[self setUserInteractionEnabled:YES];
[self setMaze:[[Maze alloc] initWithSize:MazeSizeMake(4, 6)]];
}
return self;
}
- (void)setMaze:(Maze *)newMaze {
maze = newMaze;
CGRect newFrame = [self frame];
newFrame.size = CGSizeMake([newMaze size].width * kCellSidesSize,
[newMaze size].height * kCellSidesSize);
[self setFrame:newFrame];
}
- (void)setInterfaceOrientation:(UIInterfaceOrientation)newOrientation {
if (interfaceOrientation != newOrientation) {
interfaceOrientation = newOrientation;
CGRect oldFrame = [self frame];
[self setFrame:CGRectMake(oldFrame.origin.y, oldFrame.origin.x,
oldFrame.size.height, oldFrame.size.width)];
[[self superview] setContentSize:[self frame].size];
}
}
- (void)setController:(UIViewController *)newController {
if (controller != newController) {
controller = newController;
}
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
NSUInteger columns = [[self maze] size].width;
NSUInteger rows = [[self maze] size].height;
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, kCellSidesSize - 2.0);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
BOOL isDrawing = NO;
MazeCell *aCell;
NSMutableArray *aStack = [[NSMutableArray alloc] init];
NSUInteger row = 0;
NSUInteger column = 0;
while (YES) {
aCell = [maze getCellInRow:row andColumn:column ofOrientation:interfaceOrientation];
if (isDrawing) {
CGContextAddLineToPoint(context, row * kCellSidesSize + kCellSidesSize / 2.0,
column * kCellSidesSize + kCellSidesSize / 2.0);
} else {
isDrawing = YES;
CGContextMoveToPoint(context, row * kCellSidesSize + kCellSidesSize / 2.0,
column * kCellSidesSize + kCellSidesSize / 2.0);
}
if ([aCell left] == MazeCellEdgeExit && [aCell drawCount] < 1) {
//Warnings and errors
[aCell setDrawCount:1]; //Warning
column--;
} else if ([aCell right] == MazeCellEdgeExit && [aCell drawCount] < 2) {
//Warnings and errors
[aCell setDrawCount:2]; //Warning
column++;
} else if ([aCell up] == MazeCellEdgeExit && [aCell drawCount] < 3) {
//Warnings and errors
[aCell setDrawCount:3]; //Warning
row--;
} else if ([aCell down] == MazeCellEdgeExit && [aCell drawCount] < 4) {
//Warnings and errors
[aCell setDrawCount:4]; //Warning
row++;
} else if ([aStack count] > 0) {
aCell = [aStack pop];
row = [aCell row]; //Warning
column = [aCell column]; //Warning
isDrawing = NO;
} else {
break;
}
}
CGContextStrokePath(context);
[aStack release];
}
#end
Again, this is provided to prove that I have coded things. This program works and, as I said, the maze cell methods actually do work, it's just that Xcode is giving me warnings which I wouldn't care about, except that it says I haven't defined MazeCellEdgeExit and so doesn't compile anymore, but it does compile otherwise.
Now this is quite strange. But I have discovered that duplicating the MazeCell.h and MazeCell.m files and renaming them to MzCell.h and MzCell.m, and then replacing every reference to MazeCell with MzCell got this program to run.
Although that opens up more questions than it answers...
Everything looks good to me. Try a clean and build. It's quite possible that outdated object files are floating around, confusing the compiler or linker.
I haven't been able to detect a bug that would prevent compilation, although there are a number of apparent memory leaks, such as in setMaze: where you don't release the old maze. (You definitely allocate a maze in -initWithFrame: so you leak at least that one.) Also, the default setter semantic is "assign", not "retain" or "copy" — in this case, it would seem that one of the latter two behaviors would make more sense. I realize you're new to Objective-C, so these are meant by way of constructive feedback, not criticism. :-)
You neglect to include the code that's actually generating the warnings, but it sounds like wherever it is, you haven't imported the MazeCell.h header file.
It's possible that the object ('MazeView') you're alloc'ing and init'ing might not be a 'MazeCell' object. This may be caused by neglecting to import the MazeCell.h as Chuck mentioned or your simply creating the 'MazeView' object with the wrong class, maybe as a result of copy and pasting your own code (just a guess, as it seems counter-intuitive to create an object of a MazeCell type and name it 'MazeView').
I also suspect, though don't have access right now to Xcode to test, that your typedef might be declared incorrectly (or I'm simply not familiar with that syntax style). Try replacing your 6 lines of the typedef with this.
typedef enum {
MazeCellEdgeWall = 0,
MazeCellEdgeGate = 1,
MazeCellEdgeExit = 2
} MazeCellEdge;
EDIT:
Since you have just included the implementation file, I noticed that it's for MazeView (line 7), but your original header file is for MazeCell. So as of right now, you actually haven't written any code (or not posted any) that is actually for a MazeCell object.
I'm also suspecting that you haven't #synthesize'ed (or written methods for them) any of your instance variables.