Best iphone questions in July 2011

Matt Gallagher's UITableView (Revisited) + NSFetchedResultsController

13 votes

Screenshot

If you look at Matt Gallagher's Cocoa With Love blog, he has a brilliant discussion (with sample code) on a fresh a beautiful retake on UITableView ... In the post, he talks about it's great many benefits of animations and heterogeneous cells, etc. However, one of the limitations he lists is a bit of a show-stopper for me. It won't work with NSFetchedResultsController. The design of loading data into the cells assumes that all that data is static and available immediately. However, if you are building a table with many rows and your data consists of objects in Core Data, your view controller would likely benefit greatly if you had access to the cacheing and dynamic loading capability of FRC.

My question: Has anyone put any effort into re-tasking his revisited UITableView design for use with NSFetchedResultsController? If someone's already done it (or is working on it), I would love (LOVE) to try it in my work or even help develop it.

Ha! Good to go... Changed Table Revisited, To support the Core Data Download.

What is the best way to deal with the NSDateFormater locale "feature"?

12 votes

It seems that NSDateFormater has a "feature" that bites you unexpectedly: If you do a simple "fixed" format operation such as:

NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];

Then it works fine in the US and most locales UNTIL ... someone with their phone set to a 24-hour region sets the 12/24 hour switch in settings to 12. Then the above starts tacking "AM" or "PM" onto the end of the resulting string.

(See, eg, NSDateFormatter, am I doing something wrong or is this a bug?)

(And see http://developer.apple.com/library/ios/#qa/qa1480/_index.html)

Apparently Apple has declared this to be "BAD" -- Broken As Designed, and they aren't going to fix it.

The circumvention is apparently to set the locale of the date formatter for a specific region, generally the US, but this is a bit messy:

NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];

Not too bad in onsies-twosies, but I'm dealing with about ten different apps, and the first one I look at has 43 instances of this scenario.

So any clever ideas for a macro/overridden class/whatever to minimize the effort to change everything, without making the code to obscure? (My first instinct is to override NSDateFormatter with a version that would set the locale in the init method. Requires changing two lines -- the alloc/init line and the added import.)

Added

This is what I've come up with so far -- seems to work in all scenarios:

@implementation BNSDateFormatter

-(id)init {
static NSLocale* en_US_POSIX = nil;
NSDateFormatter* me = [super init];
if (en_US_POSIX == nil) {
    en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
[me setLocale:en_US_POSIX];
return me;
}

@end

Bounty!

I'll award the bounty to the best (legitimate) suggestion/critique I see by mid-day Tuesday. [See below -- deadline extended.]

Update

Re OMZ's proposal, here is what I'm finding --

Here is the category version -- h file:

#import <Foundation/Foundation.h>


@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end

Category m file:

#import "NSDateFormatter+Locale.h"


@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX = nil;
self = [super init];
if (en_US_POSIX == nil) {
    en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX.description, [en_US_POSIX localeIdentifier]);
[self setLocale:en_US_POSIX];
return self;    
}

@end

The code:

NSDateFormatter* fmt;
NSString* dateString;
NSDate* date1;
NSDate* date2;
NSDate* date3;
NSDate* date4;

fmt = [[NSDateFormatter alloc] initWithSafeLocale];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];  
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"]; 
NSLog(@"date4 = %@", date4.description);
[fmt release];

fmt = [[BNSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];  
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"]; 
NSLog(@"date4 = %@", date4.description);
[fmt release];

The result:

2011-07-11 17:44:43.243 DemoApp[160:307] Category's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.257 DemoApp[160:307] dateString = 2011-07-11 05:44:43 PM
2011-07-11 17:44:43.264 DemoApp[160:307] date1 = (null)
2011-07-11 17:44:43.272 DemoApp[160:307] date2 = (null)
2011-07-11 17:44:43.280 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.298 DemoApp[160:307] date4 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.311 DemoApp[160:307] Extended class's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.336 DemoApp[160:307] dateString = 2011-07-11 17:44:43
2011-07-11 17:44:43.352 DemoApp[160:307] date1 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.369 DemoApp[160:307] date2 = 2001-05-06 03:34:56 AM +0000
2011-07-11 17:44:43.380 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.392 DemoApp[160:307] date4 = (null)

The phone [make that an iPod Touch] is set to Great Britain, with the 12/24 switch set to 12. There's a clear difference in the two results, and I judge the category version to be wrong. Note that the log in the category version IS getting executed (and stops placed in the code are hit), so it's not simply a case of the code somehow not getting used.

Bounty update:

Since I haven't gotten any applicable replies yet I'll extend the bounty deadline for another day or two.

Bounty ends in 21 hours -- it'll go to whoever makes the most effort to help, even if the answer isn't really useful in my case.

A curious observation

Modified the category implementation slightly:

#import "NSDateFormatter+Locale.h"

@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX2 = nil;
self = [super init];
if (en_US_POSIX2 == nil) {
    en_US_POSIX2 = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX2.description, [en_US_POSIX2 localeIdentifier]);
[self setLocale:en_US_POSIX2];
NSLog(@"Category's object: %@ and object's locale: %@ %@", self.description, self.locale.description, [self.locale localeIdentifier]);
return self;    
}

@end

Basically just changed the name of the static locale variable (in case there was some conflict with the static declared in the subclass) and added the extra NSLog. But look what that NSLog prints:

2011-07-15 16:35:24.322 DemoApp[214:307] Category's locale: <__NSCFLocale: 0x160550> en_US_POSIX
2011-07-15 16:35:24.338 DemoApp[214:307] Category's object: <NSDateFormatter: 0x160d90> and object's locale: <__NSCFLocale: 0x12be70> en_GB
2011-07-15 16:35:24.345 DemoApp[214:307] dateString = 2011-07-15 04:35:24 PM
2011-07-15 16:35:24.370 DemoApp[214:307] date1 = (null)
2011-07-15 16:35:24.378 DemoApp[214:307] date2 = (null)
2011-07-15 16:35:24.390 DemoApp[214:307] date3 = (null)
2011-07-15 16:35:24.404 DemoApp[214:307] date4 = 2001-05-05 05:34:56 PM +0000

As you can see, the setLocale simply didn't. The locale of the formatter is still en_GB. It appears that there is something "strange" about an init method in a category.

Duh!!

Sometimes you have an "Aha!!" moment, sometimes it's more of a "Duh!!" This is the latter. In the category for initWithSafeLocale the "super" init was coded as self = [super init];. This inits the SUPERCLASS of NSDateFormatter but does not init the NSDateFormatter object itself. Apparently when this initialization is skipped, setLocale "bounces off", presumably because of some missing data structure in the object. Changing the init to self = [self init]; causes the NSDateFormatter initialization to occur, and setLocale is happy again.

Here is the "final" source for the category's .m:

#import "NSDateFormatter+Locale.h"

@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
    static NSLocale* en_US_POSIX = nil;
    self = [self init];
    if (en_US_POSIX == nil) {
        en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    }
    [self setLocale:en_US_POSIX];
    return self;    
}

@end

Typically, how much does it increase development time to target both iPhone and iPad?

9 votes

As opposed to targeting just iPhone? I need to make a decision on whether to target both, but I've only done iPhone development, so I can't really estimate how much longer it would take to do both an iPhone and an iPad app. Some information about what I'm trying to do:

Uses a navigation controller on iPhone, would use a split view controller on iPad

Has three separate views in a view controller in the iPhone version that I would display all in one view on the iPad version.

So I'm wondering, in general, by how much does it increase development time to target both? How rough is the answer? And also, how is the learning curve for an iPhone developer to learn to develop for iPad? This might be difficult to answer, but even rough estimates are better than none.

Well, I'll answer your questions and hope that helps.

How much does it increase development time to target both? It really depends on what you are doing. If you design your classes well, all the data would be abstracted from the UI. In which case, all you have to do is redesign the UI for the iPad and it still all hooks into the same functions and back end data. This could increase development time by 1%-100%, it really depends on your scope. Think about how long it took to design the UI for the iPhone implementation, and add that time for another design for iPad, and you'll probably be in the ball park.

How rough is the answer? Very, its all scope dependent.

And also, how is the learning curve for an iPhone developer to learn to develop for iPad? Barely any learning curve at all. They both use the iOS APIs, besides a few minor differences (popovers, split views, etc) they are pretty much exactly the same.

Objective C - Replacing portion of string in NSString?

8 votes

I am using the following code to replace a portion of the string, this works for normal characters (alphabetical characters) but when it comes to symbols like "•" it can't replace the character.

Any solution?

[myString stringByReplacingOccurrencesOfString:@"•" withString:@"<BULLET_POINT>"];

You may not be able to literally insert non-ASCII characters like "•" in a source file. Try using the escape \u2022 instead.

myString = [myString stringByReplacingOccurrencesOfString:@"\u2022" withString:@"<BULLET_POINT>"];

i want to convert NSData To double value in Iphone

8 votes

i want covert content of NSData Which is actually i need as a double type how can i convert it?

here 1ff46c56 7dd86f40 nsdata byte and i want in double

Assuming your data is exactly 8 bytes, you can convert it to a double using memcpy(3):

double ConvertNSDataToDouble(NSData *data)
{
    double d;
    assert([data length] == sizeof(d));
    memcpy(&d, [data bytes], sizeof(d));
    return d;
}

Note that this assumes that the data is in native endian format. If you know that the data is big- or little-endian, then you may need to endian-swap the bytes first.

MapView - Have Annotations Appear One at a Time

7 votes

I'm currently adding annotations to my map through a loop... but the annotations are only appearing on my map in groups. Also, on load, only about 4 annotations are actually displayed on the map... but as I move the map a little, all of the annotations that should be there, suddenly appear.

How can I get all of the annotations to load in the right place, one at a time?

Thanks in advance!

Here is the code I'm using to add annotations:

 NSString *incident;
            for (incident in weekFeed) {
                NSString *finalCoordinates = [[NSString alloc] initWithFormat:@"%@", [incident valueForKey:@"coordinates"]];

                NSArray *coordinatesArray = [finalCoordinates componentsSeparatedByString:@","]; 

                latcoord = (@"%@", [coordinatesArray objectAtIndex:0]);
                longcoord = (@"%@", [coordinatesArray objectAtIndex:1]);

                // Final Logs
                NSLog(@"Coordinates in NSString: [%@] - [%@]", latcoord, longcoord);

                CLLocationCoordinate2D coord;
                coord.latitude = [latcoord doubleValue];
                coord.longitude = [longcoord doubleValue];


                DisplayMap *ann = [[DisplayMap alloc] init]; 
                ann.title = [NSString stringWithFormat: @"%@", [incident valueForKey:@"incident_type"]];
                ann.subtitle = [NSString stringWithFormat: @"%@", [incident valueForKey:@"note"]];
                ann.coordinate = coord;

                [mapView addAnnotation:ann];

                [ann release];
                }


// Custom Map Markers
-(MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {

    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;  //return nil to use default blue dot view

    static NSString *AnnotationViewID = @"annotationViewID";
    MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];

    if (annotationView == nil) {
        annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
        }

    annotationView.canShowCallout = YES;

    if ([annotationView.annotation.title isEqualToString:@"one"]) {
        UIImage *pinImage = [UIImage imageNamed:@"marker_1.png"];
        [annotationView setImage:pinImage];
        }

    if ([annotationView.annotation.title isEqualToString:@"two"]) {
        UIImage *pinImage = [UIImage imageNamed:@"marker_2.png"];
        [annotationView setImage:pinImage];
        }

    annotationView.annotation = annotation;
    return annotationView;
    }

- (void) mapView:(MKMapView *)mapV didAddAnnotationViews:(NSArray *)views {
    CGRect visibleRect = [mapV annotationVisibleRect]; 
    for (MKAnnotationView *view in views) {
        CGRect endFrame = view.frame;

        CGRect startFrame = endFrame; startFrame.origin.y = visibleRect.origin.y - startFrame.size.height;
        view.frame = startFrame;

        [UIView beginAnimations:@"drop" context:NULL]; 
        [UIView setAnimationDuration:0.4];

        view.frame = endFrame;

        [UIView commitAnimations];
    }
}

Adam,

This solution is a bit messy as I had to munge up one of my current projects to test, but hopefully this will work for you.

First an explanation, it's critical to separate data from UI presentation. The [MKMapView addAnnotation(s)] are just a data update to MKMapView and have no direct impact on animation or timing.

The delegate method mapView:didAddAnnotationViews: is where all of the custom presentation behavior should be defined. In your description you didn't want these to appear all at once, so you need to sequence your animations instead of performing them simultaneously.

One method is to add all of the annotations at once and then just add them with increasing animation delays, however new annotations that get added for whatever reason will begin their animations at zero again.

The method below sets up an animation queue self.pendingViewsForAnimation (NSMutableArray) to hold annotation views as they are added and then chains the animation sequentially.

I've replaced the frame animation with alpha to focus on the animation problem to separate it from the issue of some items not appearing. More on this after the code...

// Interface
// ...

// Add property or iVar for pendingViewsForAnimation; you must init/dealloc the array
@property (retain) NSMutableArray* pendingViewsForAnimation;

// Implementation
// ...
- (void)processPendingViewsForAnimation
{
    static BOOL runningAnimations = NO;
    // Nothing to animate, exit
    if ([self.pendingViewsForAnimation count]==0) return;
    // Already animating, exit
    if (runningAnimations) 
        return;

    // We're animating
    runningAnimations = YES;

    MKAnnotationView* view = [self.pendingViewsForAnimation lastObject];

    [UIView animateWithDuration:0.4 animations:^(void) {
        view.alpha = 1;
        NSLog(@"Show Annotation[%d] %@",[self.pendingViewsForAnimation count],view);
    } completion:^(BOOL finished) {
        [self.pendingViewsForAnimation removeObject:view];
        runningAnimations = NO;
        [self processPendingViewsForAnimation];
    }];

}

// This just demonstrates the animation logic, I've removed the "frame" animation for now
// to focus our attention on just the animation.    
- (void) mapView:(MKMapView *)mapV didAddAnnotationViews:(NSArray *)views {
    for (MKAnnotationView *view in views) {
        view.alpha = 0;

        [self.pendingViewsForAnimation addObject:view];
    }
    [self processPendingViewsForAnimation];
}

Regarding your second issue, items are not always appearing until you move the map. I don't see any obvious errors in your code, but here are some things I would do to isolate the problem:

  1. Temporarily remove your mapView:didAddAnnotationViews:, mapView:annotationForView: and any other custom behaviors to see if default behavior works.
  2. Verify that you have a valid Annotation at the addAnnotation: call and that the coordinates are visible (use [mapView visibleMapRect], MKMapRectContainsPoint(), and MKMapPointForCoordinate().
  3. If it is still not functioning, look at where you are calling the add annotations code from. I try to avoid making annotation calls during map movement by using performSelector:withObject:afterDelay. You can precede this with an [NSObject cancelPreviousPerformRequestsWithTarget:selector:object:] to create a slight delay prior to loading annotations in case the map is being moved a long distance with multiple swipes.

One last point, to achieve the pin-drop effect you're looking for, you probably want to offset by a fixed distance from the original object instead of depending on annotationVisibleRect. Your current implementation will result in pins moving at different speeds depending on their distance from the edge. Items at the top will slowly move into place while items at the bottom will fly rapidly into place. Apple's default animation always drops from the same height. An example is here: How can I create a custom "pin-drop" animation using MKAnnotationView?

Hope this helps.

Update: To demonstrate this code in action I've attached a link to a modified version of Apple's Seismic demo with the following changes:

  1. Changed Earthquake.h/m to be an MKAnnotation object
  2. Added SeismicMapViewController.h/m with above code
  3. Updated RootViewController.h/m to open the map view as a modal page

See: http://dl.dropbox.com/u/36171337/SeismicXMLWithMapDelay.zip

Optimization of a GC language, any ideas?

7 votes

I'm a pretty big newbie when it comes to optimization. In the current game I'm working on I've managed to optimize a function and shave about 0.5% of its CPU load and that's about as 'awesome' as I've been.

My situation is as follows: I've developed a physics heavy game in MonoTouch using an XNA wrapper library called ExEn and try as I might I've found it very hard to get the game to reach a playable framerate on an iPhone4 (don't even want to think about iPhone3GS at this point).

The performance degradation is almost certainly in the physics calculations, if I turn physics off the framerate jumps up sharply, if I disable everything, rendering, input, audio and just leave physics on performance hovers around 15fps during physics intensive situations.

I used Instruments to profile the performance and this is what I got: http://i.imgur.com/FX25h.png The functions which drain the most performance are either from the physics engine (Farseer) or the ExEn XNA wrapper functions they call (notably Vector2.Max, Vector2.Min).

I looked into those functions and I know wherever it can Farseer is passing values by reference into those functions rather than by value so that's that covered (and it's literally the only way I can think of. The functions are very simple themselves basically amounting to such operations as

return new Vector2(Max(v1.x, v2.x), Max(v1.y, v2.y)) 

Basically I feel like I'm stuck and in my limited capacity and understanding of code optimizations I'm not sure what my options are or if I even have any options (maybe I should just curl into a fetal position and cry?). With LLVM turned on and built in release I'm getting maybe 15fps at best. I did manage to bring the game up to 30fps by lowering the physics precision but this makes many levels simply unplayable as bodies intersect one another and collapse in on themselves.

So my question is, is this a lost cause or is there anything I can do to beef up performance?

First of all, love your game on Windows Phone 7!

Secondly, I don't see anything out of the ordinary in your profiler output. I did a quick and dirty performance analysis of the Farseer engine once (running in .net) and came up with similar results. It almost looks like you have a slowdown that is proportional across the board and may be due to mono itself.

How to create website APIs

7 votes

I get a lot of clients asking me about making mobile apps that connect to their websites to retrieve data, allow users to login, etc. Most of them have PHP-based sites, but don't have any clue about making APIs to interface with them. They ask me why I can't just connect directly to their SQL databases. I don't think that's a good thing to do from a mobile app. I would prefer they have some sort of API in place.

As far as PHP-based sites go, what are the best options when it comes to implementing an API for this purpose?

Thanks, gb

You want to look into RESTful web services. Have a look at the wiki for this here. Your client's need to essentially build PHP applications that serve the underlying data of their websites through some REST-compliant data type e.g. JSON, XML, SOAP, etc. There are a number of in-built PHP functions that enable the quick conversion of PHP data structures into these formats. This would enable you to build mobile apps that make HTTP requests to get data which it can then display in it's own unique way.

An example for a JSON powered service could be as follows:

$action = $_GET['action'];
switch($action) {
  case 'get-newest-products':
     echo json_encode(getNewestProducts());
     break;
  case 'get-best-products':
     echo json_encode(getBestProducts());
     break;
  .
  .
  .
  default:
     echo json_encode(array());
     break;
}

function getNewestProducts($limit = 10) {
  $rs = mysql_query("SELECT * FROM products ORDER BY created DESC LIMIT $limit");

  $products = array();
  if (mysql_num_rows($rs) > 0) {
    while ($obj = mysql_fetch_object($rs)) {
      $products[] $obj;
    }
  }
  return $products;
}

function getBestProducts($limit = 10) {
  $rs = mysql_query("SELECT * FROM products ORDER BY likes DESC LIMIT $limit");

  $products = array();
  if (mysql_num_rows($rs) > 0) {
    while ($obj = mysql_fetch_object($rs)) {
      $products[] $obj;
    }
  }
  return $products;
}

You could query the API as follows (with mod_rewrite on) http://myapi.mywebsite.com/get-newest-products

Can a type declaration be made in a Switch statement?

7 votes

I am using XCode 4.0.2 for a iOS4 project.

I have a standard "Switch" statement

switch (i) {
    case 0:
        int a = 0;
    break
    ...
}

This give me an error "Expected expression" on int a = 0;.

It is very strange that "Switch" is working fine if I precede type declaration with a simple statement like this

switch (i) {
    case 0:
        b = 0;
        int a = 0;
    break
    ...
}  

in this case the compiler gives no error (only a "unused variable a" warning).

How can that be?

Thank you.

Try something like

switch (i) {
    case 0:
    {
        int a = 0;
    }
    break
    ...
}

Does upgrading to OSX Lion have ANY caveats for development using Xcode?

7 votes

Simple question, I want to know if anyone has had any weird or annoying problems with developing iphone apps in Xcode after upgrading to Lion. I remember having issues when Snow Leopard first launched. Are there any early adopter penalties here?

You have to download the latest Xcode 4.1 to do development on Lion. 4.0.x won't work.

You also have to learn how to scroll down pages like a flight simulator (you can turn it off). If you got used to the neat gestures in Snow Leopard, then get ready to completely start over again with new ones (no going back on Lion). Three finger web page navigation doesn't work, 4 finger application switching doesn't work, and a new "explosion" gesture is used for desktop and mission control.

Sort NSArray of NSStrings like Addressbook on iphone sort

7 votes

I have an array of strings (names)

and i would like to sort them like how the address book on the iphone sorts them

  • eg: éli -> under E
  • eg: àli -> under A
  • eg: 4li -> under #

any suggestions?

You need to perform a diacritic insensitive comparison against the strings. NSString has a compare:options: method with an option of NSDiacriticInsensitiveSearch.

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", @"aaron", nil];

NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

Edit:

Here is a full example that will section the results based on the first character diacritic insensitive. I put in a dictionary so you would need to keep track of the sorted keys on your own to display properly.

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", nil];

NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

NSMutableDictionary *sectioned = [NSMutableDictionary dictionary];
NSString *firstChar = nil;

for(NSString *str in sorted)
{
    //Ignore empty strings
    if(![str length])continue;

    NSMutableArray *names = nil;

    //Compare the first character using diacritic insensitive search
    if([str compare:firstChar options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch range:NSMakeRange(0, 1)] == NSOrderedSame)
    {
        names = [sectioned objectForKey:firstChar];
    }
    else
    {
        //decomposedStringWithCanonicalMapping is where the magic happens
        //(it removes the accent mark)
        firstChar = [[str decomposedStringWithCanonicalMapping] substringToIndex:1];
        names = [NSMutableArray array];
        [sectioned setObject:names forKey:firstChar];
    }

    [names addObject:str];
}

NSLog(@"sorted: %@", sorted);
//This is sectioned like the address app
NSLog(@"sectioned: %@", sectioned);

How to synchronize tasks in different dispatch queues?

7 votes

I'm new to queues and I'm having some trouble setting up the following scheme.

I have three tasks that need doing.

Task A: Can only run on the main queue, can run asynchronously with task B, cannot run asynchronously with task C. Runs a lot but runs fairly quickly.

Task B: Can run on any queue, can run asynchronously with task A, cannot run asynchronously with task C. Runs rarely, but takes a long time to run. Needs Task C to run afterwards, but once again task C cannot run asynchronously with task A.

Task C: Can run on any queue. Cannot run asynchronously with either task A or task B. Runs rarely and runs quickly.

Right now I have it like this:

Task A is submitted to the main queue by a Serial Queue X (a task is submitted to Serial Queue X to submit task A to the main queue).

Task B is submitted to Serial Queue X.

Task C is submitted to the main queue by Serial Queue X, just like task A.

The problem here is that task C sometimes runs at the same time as task B. The main queue sometimes runs task C at the same time that the serial queue runs task B.

So, how can I ensure that task B and task C never run at the same time while still allowing A and B to run at the same time and preventing A and C from running at the same time? Further, is there any easy way to make sure they run the same number of times? (alternating back and forth)

You know, I think I had this problem on my GRE, only A, B, and C were Bob, Larry, and Sue and they all worked at the same office.

I believe that this can be solved with a combination of a serial queue and a dispatch semaphore. If you set up a single-wide serial dispatch queue and submit tasks B and C to that, you'll guarantee that they won't run at the same time. You can then use a dispatch semaphore with a count set to 1 that is shared between tasks A and C to guarantee that only one of them will run at a time. I describe how such a semaphore works in my answer here. You might need to alter that code to use DISPATCH_TIME_FOREVER so that task A is held up before submission rather than just tossed aside if C is running (likewise for submission of C).

This way, A and B will be running on different queues (the main queue and your serial queue) so they can execute in parallel, but B and C cannot run at the same time due to their shared queue, nor can A and C because of the semaphore.

As far as load balancing on A and C goes (what I assume you want to balance), that's probably going to be fairly application-specific, and might require some experimentation on your part to see how to interleave actions properly without wasting cycles. I'd also make sure that you really need them to alternate evenly, or if you can get by with one running slightly more than another.

Difference between iPhone development and Mac OSX development

3 votes

This question is for all the programmers who code in iphone as well as the Mac OSX platform.

I have been searching on Google for quite some time, but I could not find any good answer, and so I am posting the question here. Please apologize if this is not a programming question.

  1. Question on development overview:

    I would like to know how the iphone development tools are different from Mac OSX development tools.

  2. Question on the programming language:

    Is the programming done in objective-c for mac-osx as well ? Will it be the same syntax and format (for example, to create a button or textField)... ?

  3. Question on the libraries:

    If the programming is done in Xcode, how will the classes and libraries for touch and navigation be for the development in Mac OSX. ? And is there an interface builder ?

  4. Question on Simulation and Testing:

    Is it as easy as iPhone development to simulate and test the app in a Simulator ?

  1. Many different UI elements and interactions.
  2. The same.
  3. Different.
  4. IMHO yes.

You may want to check out these posts to help you transition:

Jumping from iOS to OSX

Removing iOS SDKs from OSX

When we need Pointer of BOOL Variable in Objective C?

2 votes

In which case we need a pointer of a BOOL variable in Objective C language?

I have a code for collapsible UITableView in which there is a function declaration:

- (void)toggle:(BOOL*)isExpanded section:(NSInteger)section; 

and its definition is:

- (void)toggle:(BOOL*)isExpanded section:(NSInteger)section 
{
    *isExpanded = !*isExpanded; 
    NSArray *paths = [self indexPathsInSection:section];

    if (!*isExpanded)
    {
        [self.tableview deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
    }
    else 
    {
        [self.tableview insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
    }

*isExpanded = !*isExpanded; What is the meaning of this statement as I have never used this kind of statement in case of BOOL Variable.

Following are other two functions of same code which are called in the sequence of above function:

- (NSArray*)indexPathsInSection:(NSInteger)section 
{
    NSMutableArray *paths = [NSMutableArray array];
NSInteger row;
    for ( row = 0; row < [self numberOfRowsInSection:section]; row++ ) 
    {
        [paths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
    }
    return [NSArray arrayWithArray:paths];
}

- (NSInteger)numberOfRowsInSection:(NSInteger)section 
{
    return [[sectionDataArray objectAtIndex:section] count];
}

sectionDataArray is the array for number of rows in each section. I may be unclear but if you got my point please explain all this.

Here is the link to that code

Thanks

Pointers to variables (or pointer to pointers of objects) are useful, if you want to change their value in another function. If you pass a plain BOOL to a method, you can use it, but if you change it, this change is only local as it was passed by value. If you pass the pointer/address of the variable instead, you can also change its real value.

This comes in handy if you need more than one return value and don't want to wrap it up in an object. It's also a common pattern in Cocoa where NSError variables are passed as pointers, i.e -(BOOL) doSomethingError:(NSError **)error.

casting object of type id to to an unknown type at runtime

2 votes

I have a method that takes as a string the name of an entity in my sqlite database that I am trying to streamline to use as little repeating code as possible.

here I have entity as id that I am trying to set to the require object type in readiness to make the call to insert a row.

problem is when I make the call to NSEntityDescription entity is still of class id

  id entity;

if ([entityName isEqualToString:@"yadda yadda"]) {

    entity = [EntityYadda class];
}
else if ([entityName isEqualToString:@"blah blah"]) {

    entity = [EntityBlah class];
}
else if ([entityName isEqualToString:@"Foobar"]) {

    entity = [EntityFoobar class];
}

for (int x=0; x<[data count]; x++) {

    entity = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];

Where am I going wrong?

Thanks

I have 7 different entities all with identical fields so I am trying to dynamically assign the required entity class to 'entity' so in my loop I will have only one line using NSEntityDescription an property settings.

Well, you've already had the thought of "why not one entity with a flag field denoting type?", and that is an excellent question, and I would very much recommend going with that route.

If, for some reason, you cannot, you could declare the identical fields in a protocol, and then declare that these 7 entities all conform to the same protocol. In your method, your type declaration would be (instead of id): NSManagedObject<MyCustomProtocol> *.

Unable to detect portrait orientation on iPhone

2 votes

I am displaying a modal view controller when I rotate landscape. I want to remove the modal view controller when I am in portrait. For some reason, my log statement doesn't appear when I go into portrait mode.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations.
    return (interfaceOrientation == UIInterfaceOrientationPortrait ||
                   interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||
                   interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
                   interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}


-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {

        NSLog(@"showing chart");
        [self presentModalViewController:landscapeChartViewController animated:NO];
    }

    if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||
        toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        NSLog(@"dismissing chart");
        [self.parentViewController dismissModalViewControllerAnimated:NO];
    }
}

You can simplify this code a bit, might help narrow it down.

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return YES; // Return YES is the same as entering all interfaces.
}


-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {

    NSLog(@"showing chart");
    [self presentModalViewController:landscapeChartViewController animated:NO];
}

if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
    NSLog(@"dismissing chart");
    [self.parentViewController dismissModalViewControllerAnimated:NO];
    // self.parentViewController seems like a call FROM the modalViewController. 
    // This should be moved to the modalViewControllers implementation
}
}

Just from looking at it, I'm thinking you need to dismiss the modal view controller inside the modal view, not inside the parent view. So, you would use the landscape version inside your primary controller, and then add the "willAnimateRotation..." to the modal controller to handle the portrait rotation state.

Remove white square around a png image

2 votes

I have a png image of a pin. I add it as a subview onto another imageview. But when I add it I see a white square around the pin itself. How can I remove that white background. I can see that white square when I view the file in Preview application. P.S. The platform is Mac OS X Snow Leopard. I'm developing an app for iPhone.I downloaded a png image from internet.

open that image with photoshop then select layers and then u will see two layer one for your pin other for backgroundlayer.right click then delete backgroundlayer then save again.ur problem solved.

do with Layer window pan in photoshop

Render texture using Cocos 2d and Box 2d

1 votes

I have a Cocos2d and Box2D application. I have a image bubble.png. I want to draw a chain of bubbles when the user swipes the screen.

Can anyone tell me how to do this ?

Thanks

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
{
        //Add a new body/atlas sprite at the touched location
        for( UITouch *touch in touches ) {

            CGPoint location = [touch locationInView: [touch view]];
            location = [[CCDirector sharedDirector] convertToGL: location];

            b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

            CCSprite *mist=[CCSprite spriteWithFile:@"bubble.png"];
            mist.position=ccp(location.x,location.y);

            [self addChild:mist];
        }
}

Document Generator for library iphone

1 votes

I have created one library, and now I want to have its documentation, so Is there any document generator available? If yes, What I have to keep in mind while generating documents.

http://www.stack.nl/~dimitri/doxygen/

Doxygen is probably the most widely used option. Because it's not just for ObjC (Doxygen supports many other languages), the development is lively and the community quite strong. HeaderDoc (now an open source project), by comparison appears to have largely stagnated. HeaderDoc only produces HTML output, while Doxygen also produces PDF, LaTeX and many other output forms besides HTML. Even seems to recommend Doxygen, with this guide to automatically producing documentation sets, compatible with 's help viewer, from within your build process.

It's worth noting that Doxygen can read HeaderDoc-style comments, so you can write your documentation in HeaderDoc style and decide later whether to produce the final output using Doxygen or HeaderDoc.

plist segment control save issue.

1 votes

I have a issue with this peice of code, I am trying to save some data to a plist for later use, and if the user reopens the view, it should have the current segment selected for each segment control on my view.

however when I try and save the information, it crashes on the line

[array addObject:gender];

please help :) it gives EXC_BAD_ACCESS

-(IBAction)genderSelection:(id)sender
{
    if([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
    {
        gender = @"Male";
        //NSLog(gender);
    }
    else {
        gender = @"Female";
        //NSLog(gender);
    }

}

-(IBAction)contactTypeSelection:(id)sender
{
    if([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
    {
        contactType = @"a";
        //NSLog(gender);
    }
    else {
        contactType = @"b";
        //NSLog(gender);
    }

}

-(IBAction)saveData:(id)sender
{
    NSMutableArray *array = [[NSMutableArray alloc] init];

    [array removeAllObjects];

    [array addObject:field1.text];
    [array addObject:field2.text];
    [array addObject:gender];
    [array addObject:contactType];

    [array writeToFile:[self dataFilePath] atomically:YES];
    [array release];
}

-(NSString *)dataFilePath
{
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentsDirectory = [path objectAtIndex:0];

    return [documentsDirectory stringByAppendingPathComponent:kFilename];
}

-(void)viewWillAppear:(BOOL)animated
{

    NSString *filePath = [self dataFilePath];

    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
    {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];

        field1.text = [array objectAtIndex:0];
        field2.text = [array objectAtIndex:1];

        gender = [array objectAtIndex:2];
        contactType = [array objectAtIndex:3];

        if([gender isEqualToString:@"Male"])
        {
            genderSegment.selectedSegmentIndex = 0;
        }
        else
        {
            genderSegment.selectedSegmentIndex = 1;
        }

        if([contactType isEqualToString:@"a"])
        {

        }
        else
        {

        }


        [array release];
    }
}

-(IBAction)textDone:(id)sender
{
    [sender resignFirstResponder];
}



- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [gender release]; //need to release
    [contactType release]; //need to release
    [field1 release]; //need to release
    [field2 release]; //need to release
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    gender = @"Male";
    contactType = @"a";
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (void)viewDidUnload
{
    gender = nil; //need to release
    contactType = nil; //need to release
    field1 = nil ; //need to release
    field2 = nil; //need to release
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

u didn't create like this ur gender

  • (void)viewDidLoad {

        [super viewDidLoad];

    self.gender=[[NSString alloc]init];

        self.gender = @"Male";

//so something here

    // Do any additional setup after loading the view from its nib.

}

oh sorry i have answer

if u synthesize then u have use with self and dot syntax everywhere

so change everywhere ur gender to self.gender