Life as Clay

Archive for the ‘Cocoa’ Category

New Population Pyramid Generator

leave a comment »

I created a new OS X population pyramid generator application, called Pyramids. Click here to see it in the Mac App Store. It’s $0.99. If you have a Mac and need to make population pyramids with any regularity, or even just a single one, then give it a shot!

Pyramids

Dict elements for working with US Census Bureau via Cocoa

leave a comment »

I’m querying from a part of the US Census Bureau’s website that doesn’t have a public API and I needed the value codes they are using in their countries popup. I create an NSDictionary with them and then bind an NSPopUpButton to them via an NSDictionaryController. Here are the objects and keys that I use to display the values:

@"AF",	@"Afghanistan", 
@"AL",	@"Albania",                         
@"AG",	@"Algeria",                         
@"AQ",	@"American Samoa",                  
@"AN",	@"Andorra",                         
@"AO",	@"Angola",                          
@"AV",	@"Anguilla",                        
@"AC",	@"Antigua and Barbuda",             
@"AR",	@"Argentina",                       
@"AM",	@"Armenia",                         
@"AA",	@"Aruba",                           
@"AS",	@"Australia",                       
@"AU",	@"Austria",                         
@"AJ",	@"Azerbaijan",                      
@"BF",	@"Bahamas, The",                    
@"BA",	@"Bahrain",                         
@"BG",	@"Bangladesh",                      
@"BB",	@"Barbados",                        
@"BO",	@"Belarus",                         
@"BE",	@"Belgium",                         
@"BH",	@"Belize",                          
@"BN",	@"Benin",                           
@"BD",	@"Bermuda",                         
@"BT",	@"Bhutan",                          
@"BL",	@"Bolivia",                         
@"BK",	@"Bosnia and Herzegovina",          
@"BC",	@"Botswana",                        
@"BR",	@"Brazil",                          
@"BX",	@"Brunei",                          
@"BU",	@"Bulgaria",                        
@"UV",	@"Burkina Faso",                    
@"BM",	@"Burma",                           
@"BY",	@"Burundi",                         
@"CB",	@"Cambodia",                        
@"CM",	@"Cameroon",                        
@"CA",	@"Canada",                          
@"CV",	@"Cape Verde",                      
@"CJ",	@"Cayman Islands",                  
@"CT",	@"Central African Republic",        
@"CD",	@"Chad",                            
@"CI",	@"Chile",                           
@"CH",	@"China",                           
@"CO",	@"Colombia",                        
@"CN",	@"Comoros",                         
@"CF",	@"Congo (Brazzaville)",             
@"CG",	@"Congo (Kinshasa)",                
@"CW",	@"Cook Islands",                    
@"CS",	@"Costa Rica",                      
@"IV",	@"Cote d'Ivoire",                   
@"HR",	@"Croatia",                         
@"CU",	@"Cuba",                            
@"UC",	@"Curacao",                         
@"CY",	@"Cyprus",                          
@"EZ",	@"Czech Republic",                  
@"DA",	@"Denmark",                         
@"DJ",	@"Djibouti",                        
@"DO",	@"Dominica",                        
@"DR",	@"Dominican Republic",              
@"EC",	@"Ecuador",                         
@"EG",	@"Egypt",                           
@"ES",	@"El Salvador",                     
@"EK",	@"Equatorial Guinea",               
@"ER",	@"Eritrea",                         
@"EN",	@"Estonia",                         
@"ET",	@"Ethiopia",                        
@"FO",	@"Faroe Islands",                   
@"FJ",	@"Fiji",                            
@"FI",	@"Finland",                         
@"FR",	@"France",                          
@"FP",	@"French Polynesia",                
@"GB",	@"Gabon",                           
@"GA",	@"Gambia, The",                     
@"GZ",	@"Gaza Strip",                      
@"GG",	@"Georgia",                         
@"GM",	@"Germany",                         
@"GH",	@"Ghana",                           
@"GI",	@"Gibraltar",                       
@"GR",	@"Greece",                          
@"GL",	@"Greenland",                       
@"GJ",	@"Grenada",                         
@"GQ",	@"Guam",                            
@"GT",	@"Guatemala",                       
@"GK",	@"Guernsey",                        
@"GV",	@"Guinea",                          
@"PU",	@"Guinea-Bissau",                   
@"GY",	@"Guyana",                          
@"HA",	@"Haiti",                           
@"HO",	@"Honduras",                        
@"HK",	@"Hong Kong",                       
@"HU",	@"Hungary",                         
@"IC",	@"Iceland",                         
@"IN",	@"India",                           
@"ID",	@"Indonesia",                       
@"IR",	@"Iran",                            
@"IZ",	@"Iraq",                            
@"EI",	@"Ireland",                         
@"IM",	@"Isle of Man",                     
@"IS",	@"Israel",                          
@"IT",	@"Italy",                           
@"JM",	@"Jamaica",                         
@"JA",	@"Japan",                           
@"JE",	@"Jersey",                          
@"JO",	@"Jordan",                          
@"KZ",	@"Kazakhstan",                      
@"KE",	@"Kenya",                           
@"KR",	@"Kiribati",                        
@"KN",	@"Korea, North",                    
@"KS",	@"Korea, South",                    
@"KV",	@"Kosovo",                          
@"KU",	@"Kuwait",                          
@"KG",	@"Kyrgyzstan",                      
@"LA",	@"Laos",                            
@"LG",	@"Latvia",                          
@"LE",	@"Lebanon",                         
@"LT",	@"Lesotho",                         
@"LI",	@"Liberia",                         
@"LY",	@"Libya",                           
@"LS",	@"Liechtenstein",                   
@"LH",	@"Lithuania",                       
@"LU",	@"Luxembourg",                      
@"MC",	@"Macau",                           
@"MK",	@"Macedonia",                       
@"MA",	@"Madagascar",                      
@"MI",	@"Malawi",                          
@"MY",	@"Malaysia",                        
@"MV",	@"Maldives",                        
@"ML",	@"Mali",                            
@"MT",	@"Malta",                           
@"RM",	@"Marshall Islands",                
@"MR",	@"Mauritania",                      
@"MP",	@"Mauritius",                       
@"MX",	@"Mexico",                          
@"FM",	@"Micronesia, Federated States of", 
@"MD",	@"Moldova",                         
@"MN",	@"Monaco",                          
@"MG",	@"Mongolia",                        
@"MJ",	@"Montenegro",                      
@"MH",	@"Montserrat",                      
@"MO",	@"Morocco",                         
@"MZ",	@"Mozambique",                      
@"WA",	@"Namibia",                         
@"NR",	@"Nauru",                           
@"NP",	@"Nepal",                           
@"NL",	@"Netherlands",                     
@"NC",	@"New Caledonia",                   
@"NZ",	@"New Zealand",                     
@"NU",	@"Nicaragua",                       
@"NG",	@"Niger",                           
@"NI",	@"Nigeria",                         
@"CQ",	@"Northern Mariana Islands",        
@"NO",	@"Norway",                          
@"MU",	@"Oman",                            
@"PK",	@"Pakistan",                        
@"PS",	@"Palau",                           
@"PM",	@"Panama",                          
@"PP",	@"Papua New Guinea",                
@"PA",	@"Paraguay",                        
@"PE",	@"Peru",                            
@"RP",	@"Philippines",                     
@"PL",	@"Poland",                          
@"PO",	@"Portugal",                        
@"RQ",	@"Puerto Rico",                     
@"QA",	@"Qatar",                           
@"RO",	@"Romania",                         
@"RS",	@"Russia",                          
@"RW",	@"Rwanda",                          
@"TB",	@"Saint Barthelemy",                
@"SH",	@"Saint Helena",                    
@"SC",	@"Saint Kitts and Nevis",           
@"ST",	@"Saint Lucia",                     
@"RN",	@"Saint Martin",                    
@"SB",	@"Saint Pierre and Miquelon",       
@"VC",	@"Saint Vincent and the Grenadines",
@"WS",	@"Samoa",                           
@"SM",	@"San Marino",                      
@"TP",	@"Sao Tome and Principe",           
@"SA",	@"Saudi Arabia",                    
@"SG",	@"Senegal",                         
@"RI",	@"Serbia",                          
@"SE",	@"Seychelles",                      
@"SL",	@"Sierra Leone",                    
@"SN",	@"Singapore",                       
@"NN",	@"Sint Maarten",                    
@"LO",	@"Slovakia",                        
@"SI",	@"Slovenia",                        
@"BP",	@"Solomon Islands",                 
@"SO",	@"Somalia",                         
@"SF",	@"South Africa",                    
@"OD",	@"South Sudan",                     
@"SP",	@"Spain",                           
@"CE",	@"Sri Lanka",                       
@"SU",	@"Sudan",                           
@"NS",	@"Suriname",                        
@"WZ",	@"Swaziland",                       
@"SW",	@"Sweden",                          
@"SZ",	@"Switzerland",                     
@"SY",	@"Syria",                           
@"TW",	@"Taiwan",                          
@"TI",	@"Tajikistan",                      
@"TZ",	@"Tanzania",                        
@"TH",	@"Thailand",                        
@"TT",	@"Timor-Leste",                     
@"TO",	@"Togo",                            
@"TN",	@"Tonga",                           
@"TD",	@"Trinidad and Tobago",             
@"TS",	@"Tunisia",                         
@"TU",	@"Turkey",                          
@"TX",	@"Turkmenistan",                    
@"TK",	@"Turks and Caicos Islands",        
@"TV",	@"Tuvalu",                          
@"UG",	@"Uganda",                          
@"UP",	@"Ukraine",                         
@"AE",	@"United Arab Emirates",            
@"UK",	@"United Kingdom",                  
@"US",	@"United States",                   
@"UY",	@"Uruguay",                         
@"UZ",	@"Uzbekistan",                      
@"NH",	@"Vanuatu",                         
@"VE",	@"Venezuela",                       
@"VM",	@"Vietnam",                         
@"VI",	@"Virgin Islands, British",         
@"VQ",	@"Virgin Islands, U.S.",            
@"WF",	@"Wallis and Futuna",               
@"WE",	@"West Bank",                       
@"WI",	@"Western Sahara",                  
@"YM",	@"Yemen",                           
@"ZA",	@"Zambia",                          
@"ZI",	@"Zimbabwe", 

Written by Clay

November 30, 2012 at 13:50

Posted in Cocoa, Objective-C, Resource

Obj-C Voronoi library

with 6 comments

I ported Raymond Hill’s excellent Javascript-Voronoi library to Objective-C. You can find it on github here: https://github.com/ccheaton/objcvoronoi

 

Written by Clay

March 28, 2012 at 21:08

Cocoa Programming for Mac OS X, 4th Edition: Chapter 3 Challenge

leave a comment »

Howdy. I previously wrote some entries about the solutions to the challenges in the Cocoa Programming book, 3rd Edition, by Aaron Hillegass. The 4th edition is good. Like the first edition, however, I find the description of the challenges to be a little vague.

I think he does that on purpose. The solutions usually are simpler than they appear.

The Chapter 3 challenge is, “NSDateFormatter’s setDateFormat: to customize the format string on the date objects in your LotteryEntry class.”.

Here’s what you do.

  • Look for NSDateFormatter in the Xcode documentation. Once you find it, search for the setDateFormat: method. You’ll find that you have to send a string to the method. Perhaps most useful is a link at the top of the class to the “Data Formatting Guide.” Once there, click to the “Date Formatters” page. Aha… here’s where the good info it.
  • Search again for the method name — but only search on this page — for setDateFormat:. You’ll find examples of the type of string that you can use for the date formatter. Copy one of those strings. It will look something like: @"yyyy-MM-dd 'at' HH:mm" or @"yyyy'-'MM'-'dd'T'HH':'mm':'ss"
  • Open LotteryEntry.m in your editor window and find the - (NSString *)description method implementation.
  • What you’re going to do is to replace the formatting that you entered during the chapter with your new format. Your previous method looked like:
- (NSString *)description
{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeStyle:NSDateFormatterNoStyle];
[df setDateStyle:NSDateFormatterMediumStyle];

NSString *result;
result = [[NSString alloc] initWithFormat:@"%@ = %d and %d",
[df stringFromDate:entryDate],
firstNumber, secondNumber];
return result;
}
  • You want to replace the messages that your sending to your date formatter. Your new method should look like this (with the date string you found):
- (NSString *)description
{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd 'at' HH:mm"];

NSString *result;
result = [[NSString alloc] initWithFormat:@"%@ = %d and %d",
[df stringFromDate:entryDate],
firstNumber, secondNumber];
return result;
}

That’s it! Run your program and look at the log to see the new format. You can browse through the documentation a bit more to learn more about creating custom formats.

Written by Clay

January 25, 2012 at 16:14

Posted in Cocoa, Objective-C, Tutorial

Tagged with , ,

Performance of a free niche app in the Mac App Store

with 2 comments

I released the free Population Pyramid Generator in the Mac App Store at the end of last week. The tool is very simple. I tried to make sure that it was stable and that it does what it claims to do without trouble. I think that I succeeded on those fronts. There certainly is room for improvement, however, and I have plans to add several features in a forthcoming revision.

My expectations upon release of the application were that maybe 50-60 people would download it. Let’s be honest: it’s a niche tool, and while useful for people who need a population pyramid, it’s pretty useless to anybody else. Part of my motivation to create it was that my business website receives a lot of hits related to population pyramids because I wrote a blog post there about them. I thought that it would be nice to provide the tool and that it potentially could help me find additional clients.

What I didn’t expect is that aggregation sites like macupdate.com would pick up the app. It turns out that a lot of people are exposed to it through those sites. It’s appearance in Google rankings received a quick boost and traffic to my company’s website skyrocketed shortly after the app became available.

In the first 5 days, the Population Pyramid Generator was downloaded nearly 450 times — ten times my expectation. It went live around 4pm EST on 02/24.

Equally surprising was the breakdown by country. This view shows only the first 4 days (due to the week cutoff in the itunesconnect interface):

Considering that I did basically zero marketing of this app, what’s the lesson here? I think that simple free tools, especially ones that fill an unmet niche, can be relatively effective marketing tools for a business. All told, it took me ~ 1.5 weeks to build the Population Pyramid Generator. As people with need for such a tool find and download it, perhaps I’ll gain an additional client or two. That would be worth the time investment alone. In fact, the increase in Google rankings following the release of the app probably make it worth the time investment.

The Population Pyramid Generator is a fun experiment for me and I look forward to adding additional features to it, as time allows. I also plan to create a similar tool for Windows (and use it as a project to teach myself .NET and C#).

Written by Clay

March 1, 2011 at 08:40

Connecting NSOutlineView to Core Data in 10.6 Part 1: Ordered Trees

NOTE: This tutorial is now outdated. I’m leaving it here for posterity, but please know that it may not work.

There are aspects to Cocoa that I find extremely obtuse and difficult to implement. I’m relatively new both to programming and Cocoa, and I suspect that others in the same boat also are frustrated by these steps. The single most frustrating simple thing that I have come across is implementing an NSOutlineView that connects to a Core Data model. There are several ways to approach this problem; primarily with or without Cocoa Bindings and with or without sorting.

There is a good, but outdated tutorial on how to make this work at this link: http://allusions.sourceforge.net/articles/treeDragPart1.php

The primary problem with the tutorials is that it requires the use of private Apple methods, which means that anything you build with it will not be accepted into the Mac App Store. This tutorial draws very heavily on that tutorial, with updated screenshots and code that does not use private APIs. The code also is difficult to read on that page, so it’s updated here in an easier-to-read format. Oh, and one more thing: the example on that page uses a feature of Interface Builder that no longer exists – subclassing within IB.

This tutorial is done with Xcode 3.2.5 on OS X 10.6.6.

The tutorial continues after the break…

Read the rest of this entry »

Written by Clay

February 13, 2011 at 09:31

Cocoa: How to close the system color picker panel

with 3 comments

I have a color well in the preferences sheet of the app that I’m building. When I selected a color and then closed the preferences sheet, the system color panel did not automatically close. I googled this and didn’t find an answer immediately, so I searched through the docs. This is the method that I use to close the preferences sheet now:

-(IBAction) hidePreferencesSheet:(id)sender {
	[NSApp endSheet:preferencesSheet];

	if ([NSColorPanel sharedColorPanelExists]) {
		[[NSColorPanel sharedColorPanel] close];
	}

	[preferencesSheet orderOut:sender];
}

Basically, NSColorPanel is the class that you’re dealing with. The class method +(BOOL)sharedColorPanelExists tells you whether the panel is open. NSColorPanel is a subclass of NSWindow. I use [NSColorPanel sharedColorPanel] to return the system color panel and then the NSWindow close method to close it. Pretty simple!

Written by Clay

January 22, 2011 at 10:10

Posted in Cocoa, Objective-C