There is no straightforward built in functionality for this. What you can do is create the blue dots (or whatever image you like) and set the cell.imageView.image property. I asked on stackoverflow about a problem I faced which is the images weren’t looking nice when a cell is selected. Here is how it looked (first image for “unread” cells and second for “read” cells)


What is needed is to set a transparent background for the images. Thanks to this post I found a way of masking the images. I’m using the function posted on that website with the following images. Blue dot for “unread” cells, white dot for “read” mails, and the mask image. Feel free to use these images but they are not the typical shiny iphone images. If you know how to make one of those please comment.

Posted in: Uncategorized
I’m playing with core-plot recently
I wanted to draw a bar plot such as this,
The first problem I had was the default settings gave me bars that are too thin. I wanted bars that are bit wider but not too wide. The slimmest bars would be strips of lines. The widest bars would take up a full slot, for example one bar would start on the 0 mark on the x-axis and end on the 1 mark, the other starts on 1 and ends on 2, etc. Wide bars may be interesting to some people though. I thought they make my graph look too cluttered so I decided that a reasonable width would be half of the distance between successive marks. My second requirement was the marks on the x-axis should divide bars into two equal halves (as shown). This post is how I managed to do this particular task. I don’t put a full code listing here but I’m happy to do so if anyone is interested. There is some code listing in my previous post about my first go on line plot. If you are serious about core-plot, having the API will be useful.
Create the bar plot first,
CPBarPlot* barPlot = [[[CPBarPlot alloc] initWithFrame:self.mGraph.defaultPlotSpace.graph.bounds] autorelease];
barPlot.identifier = @"MyBarPlot";
barPlot.dataSource = self;
To set the width of bars we need to first find the length of the x-axis the total length of the x-axis. The first line below takes the total width of the iphone screen, which is 320 (assuming portrait here). Graphs have left and right paddings. The second line subtracts those.
double spaceAvailableOnXaxis =320;
spaceAvailableOnXaxis = spaceAvailableOnXaxis - (self.mGraph.paddingLeft + self.mGraph.paddingRight);
We now set the width of a bar. Because each bar is half as wide as the distance between successive marks, the width would be the length of the x-axis divided by twice the number of marks. I put “4″ in the code below because my x-axis has four marks.
barPlot.barWidth = spaceAvailableOnXaxis/(4*2);
Next we need to tell core-plot where to start plotting the bars. The tricky part here is this should be specified in terms of bar width. So if you specify “3″, the first bar will be drawn at a distance (3*barwidth) from the beginning of the x-axis, and not at a distance of 3.0. In the graph shown above, I want the first bar to appear at mark 1 on the x-axis. As we said earlier, the distance between 0 and 1, which is the distance between successive marks, is twice the width of a bar. So we do,
barPlot.barOffset = 2;
We now have this graph
What gives? Before all this story started, I had to set the length of my x-axis. I did,
double xAxisLengthOriginal = 4.0; //ignore the "Original" part of the variable for now, it'll become clear soon
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)self.mGraph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(xAxisLengthOriginal)];
It is a good idea to consider the datapoints being plotted to decide how long the x-axis should be so as to make good use of the space available. But the the effect of leaving the length of the x-axis to the maximum value of our x-axis data (in this case 4.0) results in a graph that goes right up to the boundary. In the bar plot we have here it certainly is not desirable. Even in a line plot, the right most data point in this scenario will be too far to the right that it looks as if some part of the graph was cut out. One way of leaving slack space is to do as such,
double xAxisLengthOriginal = 4.0;
xAxisLength = xAxisLengthOriginal + 0.2*xAxisLengthOriginal
The result is this.
We have extra space as planned. But because the length of the x-axis has changed, it is messing up our previous calculation of the bar width. The bars are a little bit wider than we want them to be. So before setting the bar width we add the line,
spaceAvailableOnXaxis = spaceAvailableOnXaxis*(xAxisMaxOriginal/xAxisMax);
This reverses the effects of our earlier “slack space surgery”. So to summarize, prepare the plot space:
double xAxisLengthOriginal = 4.0;
xAxisLength = xAxisLengthOriginal + 0.2*xAxisLengthOriginal
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)self.mGraph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(xAxisLength)];
...
Then the bar plot:
CPBarPlot* barPlot = [[[CPBarPlot alloc] initWithFrame:self.mGraph.defaultPlotSpace.graph.bounds] autorelease];
barPlot.identifier = @"MyBarPlot";
barPlot.dataSource = self;
double spaceAvailableOnXaxis =320;
spaceAvailableOnXaxis = spaceAvailableOnXaxis - (self.mGraph.paddingLeft + self.mGraph.paddingRight);
spaceAvailableOnXaxis = spaceAvailableOnXaxis*(xAxisMaxOriginal/xAxisMax);
barPlot.barWidth = spaceAvailableOnXaxis/(4*2);
barPlot.barOffset = 2;
Hope this helps someone out there
Posted in: Objective C, iPhone
This post is about how to generate the documentation for core-plot, a graph plotting framework for Cocoa. As the project’s documentation page explains, they use Doxygen to document their code. I followed the steps below to generate the docs.
1. Download and install Graphviz. This is required by Doxygen.
2. Download and install Doxygen.
3. Open Doxygen (type “Doxygen” in spotlight).
4.1 First step is to specify the working directory for Doxygen. I created an empty directory “doxygen-working-dir” for this purpose (I later saved my doxygen settings in this directory). I then gave the project name “core-plot”, and set the source directory box to “core-plot/framework/Source”. I created an empty directory for the destination too.
4.2 I then went to “Run” tab and pressed “Run doxygen”. That generated HTML and Latex output.
EDIT
You can download the docs I generated here. The license file that comes with it is bundled in the zip file. Remember that you’re best generating the docs yourself from the latest source code though.
Posted in: iPhone
Have you ever had an icon stuck on your screen? Some icon you have, probably on your desktop, simply sits there on top of all windows you open. It’s not clickable. It occasionally blocks your view and when it doesn’t, you somehow feel it’s presence all the time. Very annoying. This is some redraw/refresh problem of course. I have tried pressing CTRL+ALT+DELETE in hope that the icon goes away, playing a video with Windows Media Player, turning on my screen saver,… nothing worked. But today I found a solution! The icon went away when I clicked on a random icon from my Quick Launch and started to drag it. Don’t waste your time logging out and back in.
Posted in: Uncategorized
This took annoyingly long time to figure out. There isn’t much info on the web about it surprisingly. Table view comes with Edit/Done buttons automatically and most info out there is about table views. I had my own view with text field controls and such. I wanted to have an Edit button. When pressed, it changes to Save with blue background and displays edit controls that are normally not there. Here goes,
- (void)viewDidLoad {
[super viewDidLoad];
mBarButtonItemEdit = [[UIBarButtonItem alloc] initWithTitle:@"Edit" style:UIBarButtonItemStyleBordered target:self action:@selector(editButtonPressed)];
mBarbuttonitemSave = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(editButtonPressed)];
self.navigationItem.rightBarButtonItem = mBarButtonItemEdit;
}
I used a boolean inside the function editButtonPressed to know the state (Edit or Save state). Nice and easy.
Posted in: Objective C, Uncategorized, iPhone
I was looking at ways to declare a protocol without defining, if such a thing makes sense. By declare I mean somehow telling the compiler the name of a protocol only, without defining the methods that should be adopted. This is similar to @class for classes,
@class MyClass;
The reason I wanted to do so was because I had a header file that looked like this,
@interface MyClass {
id mDelegate;
}
@property (nonatomic, retain) id mDelegate;
@end
@protocol MyDelegateProtocol
- (void) doStuff;
@end
This works fine. However, I don’t like the following because I’m not being specific on the type for mDelegate,
id mDelegate;
Being a Java programmer, I instinctively tried MyDelegateProtocol* mDelegate, which doesn’t work. The solution is to move the protocol definition before the interface declaration and use id<MyDelegateProtocol>,
@protocol MyDelegateProtocol
- (void) doStuff;
@end
@interface MyClass {
id<MyDelegateProtocol> mDelegate;
}
@property (nonatomic, retain) id<MyDelegateProtocol> mDelegate;
@end
I then got the error
-release not found in protocol(s)
Inheriting from NSObject did the trick,
@protocol MyDelegateProtocol <NSObject>
Posted in: Objective C, Uncategorized
The following code kept giving me EXC_BAD_ACCESS,
NSError* error;
NSMutableArray* configurationArray = [[mManagedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (error != nil) {
NSLog(@"Error: %@", error);
}
Apple has a list of suggestions on what might be causing this. However my problem was different, which was that I wasn’t initializing error pointer as such,
NSError* error = nil;
I miss Java
Posted in: Objective C, iPhone
This took me about an hour to figure out so I’m blogging it. I was interested to show a modal view with a navigation bar at the top. I wanted the navigation bar so as to put a descriptive title for the modal view. I read one solution here which is to use a label to show the title. But I kind of like the look of navigation bars at the top. Besides, the HIG from Apple shows a modal view with a navigation bar so I think showing the title this way is an accepted approach.
I added a navigation bar in the Xib file but the navigation bar was not showing in the modal view. I fiddled with some other options with no luck. Thanks to this discussion which showed me the right way.
What I did was change my original code,
DatePickerViewController *datePickerViewController = [[DatePickerViewController alloc] initWithNibName:@"DatePickerViewController" bundle:nil];
[self presentModalViewController:datePickerViewController animated:YES];
to this,
DatePickerViewController *datePickerViewController = [[DatePickerViewController alloc] initWithNibName:@"DatePickerViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:datePickerViewController];
[self presentModalViewController:navigationController animated:YES];
and my modal view has,
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Set date and time";
}

I still don’t understand why adding the navigation bar in the Xib file did not work. Maybe there is something more fundamental I am missing. I’ve spent too much time on this already though, time to move on!
Posted in: Objective C, iPhone
Follow these steps
Your objects should adopt NSCoding
First thing is elements of your array should adopt the NSCoding protocol. Some classes such as NSString and NSDate already adopt this protocol. So you will be fine if your array is full of objects that already adopt NSCoding. However, you must do a tiny bit of work if you have a custom class of your own or some other class that is not NSCoding friendly. There is a nice tutorial about this. The gist of it is if the elements of your array are objects of type MyClass then adopt NSCoding in the header file,
#import <Foundation/NSCoder.h>
@interface MyClass : NSObject <NSCoding> {…}
In my situation MyClass has two instance methods, one is of type NSDate and the other is integer. I want both of these to be persisted. So in MyClass.m I implement the two methods required by NSCoding as such,
-(void) encodeWithCoder: (NSCoder *) encoder
{
[encoder encodeObject: myDateVarialbe];
[encoder encodeObject: [NSNumber numberWithInteger:myIntegerVariable]];
}
-(id) initWithCoder: (NSCoder *) decoder
{
myDateVariable = [[decoder decodeObject] retain];
myIntegerVariable = [[[decoder decodeObject] retain] intValue];
return self;
}
As you might have guessed, the first method gets called while encoding and the second while decoding. The array is now ready to be encoded.
NSMutableArray to NSData
NSData* myData = [NSKeyedArchiver archivedDataWithRootObject:myMutableArray];
NSData to NSMutableArray
NSMutableArray* myMutableArray = [NSKeyedUnarchiver unarchiveObjectWithData:myData];
Here I’m using NSKeyedArchiver and its counterpart NSKeyedUnarchiver. There are other archivers too. I chose NSKeyedArchiver because the documentation says it supports backward compatibility better.
Posted in: Objective C, iPhone
I followed Using Core Plot in an iPhone Application to generate a graph. I got some errors though. I originally wanted to comment on the tutorial page but wasn’t allowed to. The errors,
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:106: error: incompatible type for argument 1 of 'setMajorIntervalLength:'
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:113: error: request for member 'axisLabelOffset' in something not a structure or union
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:115: error: incompatible type for argument 1 of 'setMajorIntervalLength:'
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:122: error: request for member 'axisLabelOffset' in something not a structure or union
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:125: error: request for member 'bounds' in something not a structure or union
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:135: error: request for member 'defaultPlotSymbol' in something not a structure or union
/Users/tilaye/Desktop/apps/CorePlotTest/Classes/CorePlotTestViewController.m:138: error: request for member 'bounds' in something not a structure or union
replaced axisLabelOffset with labelOffset,
I did the following to work around the issue,
replaced axisLabelOffset with labelOffset
replaced graph.defaultPlotSpace.bounds with graph.defaultPlotSpace.graph.bounds
replaced [NSDecimalNumber decimalNumberWithString:@"5"] with [[NSDecimalNumber decimalNumberWithString:@"5"] decimalValue]
My final working viewDidLoad method was then,
- (void)viewDidLoad {
[super viewDidLoad];
graph = [[CPXYGraph alloc] initWithFrame: self.view.bounds];
self.view = [[CPLayerHostingView alloc]initWithFrame:[UIScreen mainScreen].bounds];
CPLayerHostingView *hostingView = (CPLayerHostingView *)self.view;
hostingView.hostedLayer = graph;
graph.paddingLeft = 20.0;
graph.paddingTop = 20.0;
graph.paddingRight = 20.0;
graph.paddingBottom = 20.0;
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-6)
length:CPDecimalFromFloat(12)];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-5)
length:CPDecimalFromFloat(30)];
CPLineStyle *lineStyle = [CPLineStyle lineStyle];
lineStyle.lineColor = [CPColor blackColor];
lineStyle.lineWidth = 2.0f;
CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
axisSet.xAxis.majorIntervalLength = [[NSDecimalNumber decimalNumberWithString:@"5"] decimalValue];
axisSet.xAxis.minorTicksPerInterval = 4;
axisSet.xAxis.majorTickLineStyle = lineStyle;
axisSet.xAxis.minorTickLineStyle = lineStyle;
axisSet.xAxis.axisLineStyle = lineStyle;
axisSet.xAxis.minorTickLength = 5.0f;
axisSet.xAxis.majorTickLength = 7.0f;
axisSet.xAxis.labelOffset = 3.0f;
axisSet.yAxis.majorIntervalLength = [[NSDecimalNumber decimalNumberWithString:@"5"] decimalValue];
axisSet.yAxis.minorTicksPerInterval = 4;
axisSet.yAxis.majorTickLineStyle = lineStyle;
axisSet.yAxis.minorTickLineStyle = lineStyle;
axisSet.yAxis.axisLineStyle = lineStyle;
axisSet.yAxis.minorTickLength = 5.0f;
axisSet.yAxis.majorTickLength = 7.0f;
axisSet.yAxis.labelOffset = 3.0f;
CPScatterPlot *xSquaredPlot = [[[CPScatterPlot alloc]
initWithFrame:graph.defaultPlotSpace.graph.bounds] autorelease];
xSquaredPlot.identifier = @"X Squared Plot";
xSquaredPlot.dataLineStyle.lineWidth = 1.0f;
xSquaredPlot.dataLineStyle.lineColor = [CPColor redColor];
xSquaredPlot.dataSource = self;
[graph addPlot:xSquaredPlot];
CPPlotSymbol *greenCirclePlotSymbol = [CPPlotSymbol ellipsePlotSymbol];
greenCirclePlotSymbol.fill = [CPFill fillWithColor:[CPColor greenColor]];
greenCirclePlotSymbol.size = CGSizeMake(2.0, 2.0);
[xSquaredPlot setPlotSymbol:greenCirclePlotSymbol];
CPScatterPlot *xInversePlot = [[[CPScatterPlot alloc]
initWithFrame:graph.defaultPlotSpace.graph.bounds] autorelease];
xInversePlot.identifier = @"X Inverse Plot";
xInversePlot.dataLineStyle.lineWidth = 1.0f;
xInversePlot.dataLineStyle.lineColor = [CPColor blueColor];
xInversePlot.dataSource = self;
[graph addPlot:xInversePlot];
}
I also got
/Users/tilaye/Desktop/apps/TestApp/Classes/TaggedVideoGraphViewController.m:135: warning: method definition for '-numberOfRecordsForPlot:' not found
and changed my function signature from
-(NSUInteger)numberOfRecords {
to
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot {
Posted in: Objective C, iPhone