Best ios questions in October 2011

What to watch out for when transitioning to iOS 5

23 votes

Summary: Can you add to my checklist of things to watch out for when migrating to iOS 5? StackOverflow has been invaluable as I've worked on upgrading to iOS 5. I've discovered some pretty basic things I'd missed prior to Xcode 4.2, and I'm wondering what other "gotchas" might be lurking.

Detail: With iOS 5 shipping this week, I've had to make some changes to a couple of my apps. Xcode 4.2 does a much better job analyzing memory management code because of the new ARC feature. The iOS 5 update is a great point at which to review all your memory management code. The new compiler also finds a number of other issues that earlier compilers missed. Kudos to the Apple compiler engineers. Here are the main things that have helped (and many of them will also apply to earlier versions of iOS).

  1. Make sure to call [super dealloc] at the END of your dealloc methods, not the beginning.
  2. In viewDidUnload, some people have reported bugs that require [super viewDidUnload] to be called at the end, not the beginning, of your viewDidUnload.
  3. Understand retain counts, synthesized setters, and when to call release or autorelease. The new compiler will point out more problems than the older compilers did. (I thought I'd been careful, but apparently I wasn't careful enough.) Apple's memory management guide is required reading -- no shortcuts.
  4. It's a good idea to turn on zombies when debugging (in Xcode, choose Product | Edit Scheme... and select the Debug scheme; on the Diagnostics tab, check Enable Zombie Objects). This can help you find attempted uses of zombies (objects you shouldn't be using any more).
  5. The Leaks instrument is also helpful. Run your app in Profile mode and choose the Leaks template. In the Instruments window, select the Leaks instrument and check the box that says "Gather Leaked Memory Contents" and it will help you see where the leaked memory originates in your code.

There are a few odds and ends I've encountered:

    - (oneway void) release { }

Any other suggestions of potential pitfalls I should look for? I have a feeling that my apps are more stable now, but I felt pretty good about them before.

1/ Modal controllers behave differently, if you were changing their size. If you need modal dialog of a different size, consider using iOS 5 child view controllers.

2/ For a table, if you were returning nil section header and positive height, in iOS 4, the header was hidden. In iOS 5, you have to return zero height for nil headers.

3/ UDID is deprecated. You can use CFUUIDCreate to create a unique id and save it into your settings but be aware that a device data can be backed up and then restored to another device, leaving you with two devices with the same id. I solved the situation by saving my id into keychain with attribute kSecAttrAccessibleWhenUnlockedThisDeviceOnly.

About your list: [super viewDidUnload] should be always called as the last statement in your viewDidUnload. The logic is the same as in [super dealloc]. Note, that you should also call [self viewDidUnload] in your dealloc (if you don't already release your memory there) because it is not called implicitly (although sometimes it is).

From my experiments, leak detection in Instruments don't report leaks on properties which are synthesized without assigning a property name.

iCloud basics and code sample

11 votes

As a beginner, I'm struggling with iCloud. There are some samples, but they are usually quite detailed (on the developer forum there is one for iCloud and CoreData which is massive). The apple docs are OK, but I still can't see the big picture. So please bear with me, some of these questions are quite fundamental, but possibly easy to answer.

Context: I have a very simple iCloud app running (full sample code below). There is only one UITextView shown to the user and his/her input is saved in a file called text.txt.

enter image description here

The txt file is pushed to the cloud and made available to all devices. Works perfectly, but:

Main problem: What about users who do not use iCloud?

When I launch my app (see code below), I check if the user has iCloud enabled. If iCloud is enabled, everything is fine. The app goes ahead and looks for text.txt in the cloud. If found, it will load it and display it to the user. If text.txt is not found in the cloud, it will simply create a new text.txt and will display that to the user.

If the user does not have iCloud enabled, nothing will happen. How will I make it possible that non-iCloud users can still work with my text app? Or do I simply ignore them? Would I need to write separate functions for non-iCloud users? I.e. functions in which I simply load a text.txt from the documents folder?

Apple writes:

Treat files in iCloud the same way you treat all other files in your app sandbox.

However, in my case there is no 'normal' app sandbox anymore. It's in the cloud. Or do I always load my text.txt from disk first and then check with iCloud if there is something more up-to-date?

Related problem: File structure - Sandbox vs. Cloud

Perhaps my main problem is a fundamental misunderstanding of how iCloud is supposed to work. When I create a new instance of an UIDocument, I'll have to overwrite two methods. First - (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError to get files from the cloud and then -(id)contentsForType:(NSString *)typeName error:(NSError **)outError to get files into the cloud.

Do I have to incorporate separate functions which will also save a local copy of text.txt into my sandbox? Will this work for non-iCloud users? As I understand iCloud, it will save a local copy of text.txt automatically. So there shouldn't be any need for me save anything into the 'old' sandbox of my app (i.e. as it used to be in the old, pre-iCloud days). Right now, my sandbox is totally empty, but I don't know if this is correct. Should I keep another copy of text.txt in there? This feels like cluttering my data structure... as there is one text.txt in the cloud, one in the iCloud sandbox on my device (which will work even if I am offline), and a third one in the good old sandbox of my app...


MY CODE: A simple iCloud sample code

This is loosely based on an example I found in the developer forum and on the WWDC session video. I stripped it down to the bare minimum. I'm not sure that my MVC structure is any good. The model is in the AppDelegate which isn't ideal. Any suggestions to make it better are welcome.


EDIT: I tried to extract the main question and posted it [here].4


OVERVIEW:

Overview

The most important bit which loads the text.txt from the cloud:

//  AppDelegate.h
//  iCloudText

#import <UIKit/UIKit.h>

@class ViewController;
@class MyTextDocument;

@interface AppDelegate : UIResponder <UIApplicationDelegate> {
    NSMetadataQuery *_query;
}

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController *viewController;
@property (strong, nonatomic) MyTextDocument *document;

@end

//  AppDelegate.m
//  iCloudText

#import "AppDelegate.h"
#import "MyTextDocument.h"
#import "ViewController.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize viewController = _viewController;
@synthesize document = _document;

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [super dealloc];
}

- (void)loadData:(NSMetadataQuery *)query {

    // (4) iCloud: the heart of the load mechanism: if texts was found, open it and put it into _document; if not create it an then put it into _document

    if ([query resultCount] == 1) {
        // found the file in iCloud
        NSMetadataItem *item = [query resultAtIndex:0];
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];

        MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:url];
        //_document = doc;
        doc.delegate = self.viewController;
        self.viewController.document = doc;

        [doc openWithCompletionHandler:^(BOOL success) {
            if (success) {
                NSLog(@"AppDelegate: existing document opened from iCloud");
            } else {
                NSLog(@"AppDelegate: existing document failed to open from iCloud");
            }
        }];
    } else {
        // Nothing in iCloud: create a container for file and give it URL
        NSLog(@"AppDelegate: ocument not found in iCloud.");

        NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
        NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:@"text.txt"];

        MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:ubiquitousPackage];
        //_document = doc;
        doc.delegate = self.viewController;
        self.viewController.document = doc;

        [doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            NSLog(@"AppDelegate: new document save to iCloud");
            [doc openWithCompletionHandler:^(BOOL success) {
                NSLog(@"AppDelegate: new document opened from iCloud");
            }];
        }];
    }
}

- (void)queryDidFinishGathering:(NSNotification *)notification {

    // (3) if Query is finished, this will send the result (i.e. either it found our text.dat or it didn't) to the next function

    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];

    [self loadData:query];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
    _query = nil; // we're done with it
}

-(void)loadDocument {

    // (2) iCloud query: Looks if there exists a file called text.txt in the cloud

    NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
    _query = query;
    //SCOPE
    [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
    //PREDICATE
    NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K == %@", NSMetadataItemFSNameKey, @"text.txt"];
    [query setPredicate:pred];
    //FINISHED?
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
    [query startQuery];

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"AppDelegate: app did finish launching");
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    // Override point for customization after application launch.
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];
    } else {
        self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil] autorelease];
    }

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    // (1) iCloud: init

    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (ubiq) {
        NSLog(@"AppDelegate: iCloud access!");
        [self loadDocument];
    } else {
        NSLog(@"AppDelegate: No iCloud access (either you are using simulator or, if you are on your phone, you should check settings");
    }


    return YES;
}

@end

The UIDocument

//  MyTextDocument.h
//  iCloudText

#import <Foundation/Foundation.h>
#import "ViewController.h"

@interface MyTextDocument : UIDocument {

    NSString *documentText;
    id delegate;

}

@property (nonatomic, retain) NSString *documentText;
@property (nonatomic, assign) id delegate;

@end

//  MyTextDocument.m
//  iCloudText

#import "MyTextDocument.h"
#import "ViewController.h"

@implementation MyTextDocument

@synthesize documentText = _text;
@synthesize delegate = _delegate;

// ** READING **

- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError
{
    NSLog(@"UIDocument: loadFromContents: state = %d, typeName=%@", self.documentState, typeName);

    if ([contents length] > 0) {
        self.documentText = [[NSString alloc] initWithBytes:[contents bytes] length:[contents length] encoding:NSUTF8StringEncoding];
    }
    else {
        self.documentText = @"";
    }

    NSLog(@"UIDocument: Loaded the following text from the cloud: %@", self.documentText);


    // update textView in delegate...
    if ([_delegate respondsToSelector:@selector(noteDocumentContentsUpdated:)]) {
        [_delegate noteDocumentContentsUpdated:self];
    }

    return YES;

}

// ** WRITING **

-(id)contentsForType:(NSString *)typeName error:(NSError **)outError
{
    if ([self.documentText length] == 0) {
        self.documentText = @"New Note";
    }

    NSLog(@"UIDocument: Will save the following text in the cloud: %@", self.documentText);

    return [NSData dataWithBytes:[self.documentText UTF8String] length:[self.documentText length]];
}
@end

THE VIEWCONTROLLER

//
//  ViewController.h
//  iCloudText

#import <UIKit/UIKit.h>

@class MyTextDocument;

@interface ViewController : UIViewController <UITextViewDelegate> {

    IBOutlet UITextView *textView;

}

@property (nonatomic, retain) UITextView *textView;
@property (strong, nonatomic) MyTextDocument *document;

-(void)noteDocumentContentsUpdated:(MyTextDocument *)noteDocument;

@end

//  ViewController.m
//  iCloudText

#import "ViewController.h"
#import "MyTextDocument.h"

@implementation ViewController

@synthesize textView = _textView;
@synthesize document = _document;

-(IBAction)dismissKeyboard:(id)sender {

    [_textView resignFirstResponder];

}

-(void)noteDocumentContentsUpdated:(MyTextDocument *)noteDocument
{
    NSLog(@"VC: noteDocumentsUpdated");
    _textView.text = noteDocument.documentText;
}

-(void)textViewDidChange:(UITextView *)theTextView {

     NSLog(@"VC: textViewDidChange");
    _document.documentText = theTextView.text;
    [_document updateChangeCount:UIDocumentChangeDone];

}

I've been using your example and I like it for helping me grasp the basics of iCloud. Now I'm wrangling with your question for my own app which has to support existing users of the app with locally stored content who may or may not be using iCloud creating these cases as far as I can tell:

Cases:

  1. New user
    • has icloud - create documents in icloud
    • no icloud - create documents locally
  2. Existing user
    • has icloud
      • just added - migrate local docs to icloud
      • not just added - open/save docs to icloud
    • no icloud
      • just removed - migrate former icloud docs to local
      • not just removed - open/save docs to local

If someone removes iCloud - wouldn't the calls to ubiquitous URL return nil? If that's the case how do I migrate the docs back to local storage? I'll create a user pref for now but seems a bit of a workaround.

I feel like I'm missing something obvious here so if anyone can see it, please chime in.

Adding non NSObjects to NSMutableArray

10 votes

This recent SO discussion has confused me. The NSMutableArray prototype for addObject: is

- (void)addObject:(id)anObject

and id is defined in objc.h as

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id; 

When I add an NSObject or subclass to an NSMutableArray, its retain count is incremented, and when I remove it from an NSMutableArray it is decremented. Does this mean that if an id type which is not an NSObject or subclass is added to an NSMutableArray, it has to respond to retain and release messages? The definition of id does not seem to force this. Is it an objective C directive that any id type should respond to standard memory management messages?

The hard truth about most Foundation containers (and by extent most Apple-developed classes, and by extent also most classes developed by third parties) is that when a method accepts the id type, it should really read id<NSObject>, which means any type that responds to the NSObject protocol. Instances of classes that aren't part of the NSObject hierarchy are unlikely to respond to -retain and -release, which is especially inconvenient when trying to add them to a container. They're also unlikely to respond to -hash, -isEqual:, -description, -copy, and to all the other methods Foundation containers can use on their contents for whatever reason.

For instance, if you attempt to add Class objects to a Foundation container (other than NSMapTable since this one was designed with a lot of flexibility in mind), you'll hit a wall because "modern" ObjC classes are expected to inherit from NSObject, or at least implement the NSObject protocol.

This is a pretty rare situation, though. Class is pretty much the only useful class around that doesn't inherit from NSObject.

How can two developers work together on an iOS app without incorporating a company?

10 votes

Let's say two friends want to get together and build an iOS app. They want to offer the app for free and aren't looking to derive income from the project. (Alternatively a variation on this is that they will charge 99 cents for the app but don't expect it to drive a lot of sales - they are just doing it as a learning project / for the experience).

In terms of how they would setup their development program membership with Apple, it seems that Apple would advise that they incorporate a company for this and register for iOS Company account since there's multiple developers. But there are legal and accounting fees associated with incorporating a company that a free app (or low yielding app) might not offset.

So they come up with an idea of just having one of the two developers sign up for an individual account, release it under his name, and have the other be the "silent partner". If they yield a small amount of revenue they sign an agreement between them to agree to share the revenue.

Will this scenario actually work? Or will the "silent partner" not be able to build the application because he won't have the certificate? Or could he share the certificate?

It there a simpler way of doing this? It seems like a lot of hoops to jump through to work on a simple project with somebody.

You may want to look into setting it up as a 'joint venture.' A joint venture is usually set up for the purposes of some temporary project and the parties involved are to split the revenues/expenses according to some agreement. This agreement is called the 'joint venture agreement.' You can find examples online with a quick Google search.

You can apply for an EIN (Employer Identification Number) as a joint venture (using "Other" on the type of entity line), which can be used for Apple's financial information purposes for tax reporting. You can also register a "Doing Business As" (DBA) name, which depends on your local state/city rules. This would allow you to do business as something other than one of your individual names.

For tax purposes, joint venture participants just report their share of the income/expenses on their own return on Schedule C. You'd be doing this anyway, under the current scenario.

There isn't any fee to apply for an EIN, and it can be done online at the IRS website. Any fees relating to registering a DBA name depend on your local state/city.

Hope this helps! (I was an accountant for 13 years before I decided to follow my tech passion)

How to debug a Delphi iOS FireMonkey application in Xcode?

10 votes

I am trying to debug a FireMonkey application compiled with Delphi XE2 with Update 1 using Xcode v3.2.6 on Apple Snow Leopard 10.6.8. I am able to load the project in Xcode, compile it and run it in the iPhone simulator.

However, debugging does not seem to work. When I launch the project using "Run / Debug - Breakpoints On", all breakpoints in the Pascal source file which I had set in Xcode are ignored and the IDE does not interrupt the program when the code gets executed.

I have created a "Debug" configuration and in the "Deployment" options deselected the entries "Strip Debug Symbols During Code" and "Strip Linked Product". In the "Build Options" "DWARF with dSYM File" is selected as the "Debug Information Format".

I have installed the FireMonkey / Free Pascal / Xcode tools that came with Delphi XE2 with Update 1.

Solution

XCode (gdb) isn't finding your source file to link to at debug time. You can help it.

In XCode, click on the application menu and select Preferences, in the Debugging preferences clear the checkbox "Load symbols lazily" and click OK.

Rebuild, and ensure that you have breakpoints turned on. XCode should say "Build and Debug", not "Build and Run".

History

I had the same problem after following Embaracedro's instructions for configuring XCode. In the Debugging window, gdb reported the error "Warning - no location found for Unit1.pas" for the break point. After changing the debugging option as indicated above, gdb reported "Resolved" for the break point, and it worked.

Is it possible to distinguish between locking the device and sending an app to background?

9 votes

I have an app that needs to do something when it’s sent to background using the Home button and something else when the device is locked using the top hardware button. The standard way of solving these requirements are the notifications and delegate methods sent out by UIApplication. On iOS 4 they look like this:

// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.

// Pressing the lock button
Will resign active.
// Unlocking the device
Did become active.

In other words, it’s quite easy to tell between locking and backgrounding. On iOS 5 the behaviour changed:

// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.

// Pressing the lock button
Will resign active.
Did enter background.
// Unlocking the device
Will enter foreground.
Did become active.

Notice that the didEnterBackground and willEnterForeground notifications are now sent out even when (un)locking the device, making it impossible to tell between locking and backgrounding. Is this change documented somewhere? Is it a regression? Do you know another way to distinguish the two cases?

There’s a thread about this issue on Apple Developer Forums (registered developers only, sorry). The gist is that the new behaviour is by design. There are requests for a new API feature to distinguish between the two use cases, but nothing working yet.

Xcode 4.2 debug doesn't symbolicate stack call

9 votes

I have a problem with Xcode 4.2 debugging in iOS 5 simulator/device. In iOS 4.x everything is ok.

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

gives me a stack trace of hex numbers.

*** First throw call stack:

(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x6fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f92a7 0x6faa9b 0x2889 0x2805)

Thanks.

Nothing I tried would fix this (tried both compilers, both debuggers, etc.) After upgrading XCode for the iOS 5 update, no stack traces seemed to work.

However, I have found an effective work-around - creating my own exception handler (which is also useful for other reasons). First, create a function that will handle the error and output it to the console (as well as whatever else you want to do with it):

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

Next, add the exception handler to your app delegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff
}

That's it!

Is ARC really supported in iOS 4? The iOS 4.2 SDK is missing ARC-related symbols at linking time

8 votes

I've read and heard since ARC was first announced that it was a compile-time thing and would be backwards-compatible with iOS 4. I have successfully refactored my project to ARC using Xcode 4.2's automatic refactoring, and when compiled against the iOS 5.0 SDK, it works fine. However, if I try to compile against my iOS 4.2 SDK, it fails at link time, missing the following symbols:

  • _objc_retainAutoreleaseReturnValue
  • _objc_autoreleaseReturnValue
  • _objc_storeStrong
  • _objc_retain
  • _objc_release
  • _objc_retainAutoreleasedReturnValue

I checked, and these symbols are present in 5.0 but not 4.2:

iPhoneOS5.0.sdk/usr/lib $ find . -type f|xargs nm|grep -i _objc_retain$
00005ed0 T _objc_retain
000061d0 T _objc_retain

iPhoneOS4.2.sdk/usr/lib $ find . -type f|xargs nm|grep -i _objc_retain$
[... *crickets* ...]

Does this mean that Apple lied? I assume instead that I'm confused and doing something wrong, but I can't figure out what.

This is with the GM release of Xcode 4.2 (Build 4C199)

ARCis supported on iOS 4.3 and above. You need to use the iOS 5.x SDK but can select iOS 4.3 for the Deployment Target. The one thing that is not supported in 4.3 is automatic weak reference zeroing.

Oh, Xcode 4.2 is now out of NDA and can be used to submit apps.

App Store code runs different from Xcode/Device code on iPhone 3G

7 votes

I'm not sure how to explain this one. I submitted an update of one of my apps to the store yesterday. The first screenshot is how one particular screen appears running on my iPhone 3G, running iOS 4.2.1, downloaded from the App Store:

And the second image below is the exact same code, no changes have been made since the original submission, running on the exact same device tethered through Xcode.

The application runs fine on my iPhone 4, running iOS 5, downloaded from the App Store. So to recap:

  1. App obtained from App Store is flawed on iPhone 3G
  2. App obtained from App Store is good on iPhone 4
  3. App tethered through Xcode is good on iPhone 3G

These are not the only graphical inconsistencies, but they're all related to custom UITableViewCell code, which doesn't do anything more than push labels a few pixels in each directory, and has been working fine since day one. I have filed a report with idp-dts, and am waiting to hear back from them, but as the waiting list is usually a week or more, I'd rather figure this out on my own.

Any help/tips/guesses would be very appreciated!

iPhone 3G running App Store version of my application:

enter image description here

iPhone 3G running Xcode tethered version of my application:

enter image description here

Edit: This sounds quite similar to this problem: Building with LLVM and any optimization causes app to crash on startup The customer who contacted me was using a 2nd generation iPod Touch, the only other hardware other than the iPhone 3G that uses armv6.

Edit 2: Here's the snippet of code that sets the bounds of the color bar on the left side. There doesn't seem to be anything fishy going on in the code:

- (void)layoutSubviews {
    CGRect colorViewFrame = self.bounds;
    colorViewFrame.size.width = 6;
    colorViewFrame.origin.y += 3;
    colorViewFrame.origin.x -= 1;
    colorViewFrame.size.height -= 8;

    colorView.frame = colorViewFrame;
    ...
}

So here's what I found under Build Settings:

enter image description here

Which, having taken a class or two in compiler optimization, makes sense. Code debugging on a device should be left in its original state for debugging purposes, and code released should be optimized for speed and efficiency.

So here's the fun part. Changing my Debug setting to Fastest, Smallest:

enter image description here

Causes the issue to occur on my device while running tethered in Xcode.

Before filing a Radar or making any rash decisions and submitting non-optimized code to the App Store, is there anything else I should consider investigating? Was the compiler optimization really the underlying cause of the layout issues?

Edit: And if the optimization level is the issue, why does the optimized code run properly on my iPhone 4, but not properly on my iPhone 3G?

Edit 2: This problem sounds extremely similar to this answer: Building with LLVM and any optimization causes app to crash on startup

Edit 3: Heard back from Apple Radar, this is a known issue. Will be fixed in a future version of Xcode. Thanks for all the help guys!

Sharekit: url is modified while posting to facebook?

7 votes

I am posting image with image title and in the image title I have added url, I am able to share image and url also but,there is slight modification in the url.The = symbol is converted to %3D ,as shown below the both URLs(dummy url).

posted URL: http://....=418ioekVlhTIu2sr9qpdAQ==  

URL on Facebook http://...=418ioekVlhTIu2sr9qpdAQ%3D%3D

So is there any better way to post url and image in one post only or help me so that by doing some change in the code I should be able to share correct url in the Image title itself.

This happens because the URL format converts it's reserved special characters to HTML entity codes (percent escaping) as shown in here: http://www.w3schools.com/tags/ref_ascii.asp

you have 2 options to pass the URL string correctly:

  1. On the receiver side (after the URL Request is sent by the client), decode the URL string that you received, this will normalize the string back to normal.

  2. Use the POST method of html instead of the GET method to store your parameters. although I'm not sure you have an option for that.

On the iOS obj-c, Conversion between URL Percent escapes is done like so-

[normalText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[encodedText stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Back button does not appear in navigation bar until you rotate

7 votes

I have three view controllers: A -> B -> C managed by a navigation controller. A is a transient view controller. It asks the server for something. If the server says everyhing is OK, then A pushes B onto the stack. B must hide the back button because I don't want users to manually go back to A.

// B view controller
- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.navigationItem.hidesBackButton = YES;
    self.title = @"B";
}

B then pushes C onto the stack when the user taps a table cell.

// B view controller
- (void)tableView:(UITableView *)tableView 
didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    C *c = [[C alloc] 
        initWithStyle:UITableViewStyleGrouped
    ];
    [self.navigationController 
        pushViewController:c 
        animated:YES
    ];
    [c release];
}

.

// C view controller
- (void) viewDidLoad
{
    [super viewDidLoad];
    self.navigationItem.hidesBackButton = NO;
    self.title = @"C";
}

If all goes well, the flow should look like this:

-------------    -------------    -------------
|_____A_____|    |_____B ____|    | <B|__ C___|
|           | => |           | => |           |
| loading...|    |   cells   |    |   detail  |
|           |    |           |    |           |
-------------    -------------     -----------

For some reason, C does not show a back button to go back to B until I rotate the device. Once rotated, the back button appears in all orientations. The problem seems to stem from B hiding the back button and C trying to reveal it again, because If I don't let B hide it, I don't have this problem. So how do I get C to show the back button without forcing the user to rotate the device like a monkey?

Update

  • Broken on two different Verizon iPhone 4 both on iOS 4.2.10
  • Fine on AT&T iPhone 3GS on iOS 5.0
  • Fine on AT&T iPhone 4 on iOS 4.3

After some searching I found this solution for iPhone 4.2 (since you posted that it works on later versions) on some old forum post.

-(void)viewDidLoad { 
                     [super viewDidLoad];
                     self.navigationItem.hidesBackButton = YES; 
                   }

-(void)viewDidAppear:(BOOL)animated { 
                                       [super viewDidAppear:animated];
                                       self.navigationItem.hidesBackButton = NO; 
                                    }

Mayhaps this will help you out. (Check this out: Back button don't appear in navigationController)