Best ios questions in May 2012

How to restart app if it unexpectedly shutdown

17 votes

Skype update text contains next:

App auto restarts if unexpectedly shut down

How is possible to perform that via SDK?

As far as I know, some sort of apps can be run in background and can be restarted in specific case. This is from Apple docs

https://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/doc/uid/TP40007125

If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the application:didFinishLaunchingWithOptions: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application was launched because of a location event.

My opinion is: Skype is relaunched with remote notifications mechanism.

Update

Well, I think I found something. @Malek_Jundi was half-right. Your app should fail with non-zero exit code, but it should be registered as VoIP application.

Because VoIP applications need to stay running in order to receive incoming calls, the system automatically relaunches the application if it exits with a nonzero exit code. (This could happen in cases where there is memory pressure and your application is terminated as a result.) However, terminating the application also releases all of its sockets, including the one used to maintain the VoIP service connection. Therefore, when the application is launched, it always needs to create its sockets from scratch.

http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html#//apple_ref/doc/uid/TP40007072-CH7-SW12

How to generate development MDM/APNS certificate?

16 votes

We have taken iOS developer Enterprise account and we have received the MDM certificate which is in .pem format.We have download this mdm certificate from the portal https://identity.apple.com/pushcert/ But we don't have idea that this is production MDM certificate or development MDM certificate.

First we want to test MDM commands using development certificate and after getting MDM payloads,we can can continue for production.

So my question is how to create MDM/APNS certificate which can be used for getting MDM push notification from gateway.sandbox.push.apple.com , if this is possible.

I have gone through this pdf,but not getting fair idea about development MDM push notification.

Any help will be appreciated.

My suggestion is try production APNS you can use this production APNS for live MDM product also.

If you are following this page, then take care of few things and see the question also.

Touchscreen gestures list and names

12 votes

Where can I find a list of all (many) touchscreen gestures including complex 4 and 5 finger ones for iPad, with a reasonable technical implementation guidelines and code (C++/Java) examples?

After two days of search i have found these links:

http://en.wikipedia.org/wiki/Multi-touch#Multi-touch_gestures - simple gestures

http://blogs.computerworld.com/18672/the_lion_multitouch_gesture_guide - more complex multi-finger gestures on Apple devices

http://medialoot.com/item/40-vector-multitouch-gestures - 40 multitouch gestures

Unfortunately, nothing usable was found in the Apple's patents regarding gestures.

APNS notifications not reaching devices enrolled in Apple MDM

11 votes

Apple MDM is used. It is MDM using APNs.

  • The topic of mobileconfig is the same as the thing of Subject of APSP-XXX.pem.
  • The character string of a device token and PushMagic reached the MDM server after the setup of mobileconfig.

I sent wording of a telegram for device tokens using APNs. It is replacing by the character string of PushMagic. Although {"mdm":"xxxxxxxxxxxxx-xxxx-xxxx-xxxx"} is sent via APNs from the MDM server, iPhone is not reached.

Why is it?

Please let me know the cause considered.

Follow MDM_Protocol pdf very carefully.

If you are following this link: http://www.softhinker.com/in-the-news/iosmdmvendorcsrsigning Then verify few things.

remove the passphrase from customerPrivateKey.pem using this command

openssl rsa -in customerPrivateKey.pem -out PlainKey.pem

Then merge your APNS certificate (for example CustomerCompanyName.pem) downloaded from the portal https://identity.apple.com/pushcert/ using this command

cat CustomerCompanyName.pem PlainKey.pem > PlainCert.pem

Now this PlainCert.pem file can be used in your server as APNS/MDM certificate.

If still there is issue,please show here your device log.

Fonts become bold when changing orientation

11 votes

I use this in the html:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;">

and this in the CSS:

html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }\

also tried this:

html { -webkit-text-size-adjust: none; }

and yet for some reason this happens:

enter image description here enter image description here

Update: I tried removing all styling to see if any of my CSS is causing this, and the result was weird: when I'm not using any font rules, the font simply gets larger (it is not zoomed in since the zooming is locked by the HTML viewport attribute) also, only the small font gets larger, the headers remain the same. weird @#$%

Update 2: I played with the html/css and came to this conclusion - the only time when the text enlargement DOESN'T happen is when the text is contained inside the only element in the page - for example if all my body contains is p/span/div with text, it will not get enlarged. If I add another element with text in it, all text on page becomes enlarged in landscape mode.
I tried doing some research and looked through many mobile sites, and the result is the same - they all have this effect.

More Information than Real Solution

Based on my understanding of how things work according to this page and this page, all text will get refactored in landscape mode based on either -webkit-text-size-adjust: auto (the default for iOS) or by your setting of -webkit-text-size-adjust: 100%.

I do not believe the 100% setting is doing what you may think it is doing (an attempt to keep the text size the same). Rather, it is only affecting "how the text-inflating algorithm is applied" (per this page). I have not been able to track down exactly what that might mean; that is, what does 100% mean with respect to the inflation algorithm. My guess is, based upon this page's quote...

The first time a webpage is rendered, Safari on iOS gets the width of the block and determines an appropriate text scale so that the text is legible.

...that since the procedure happens only "the first time a webpage is rendered" that once the device is turned from portrait to landscape the inflation algorithm will "grow" the text based off the width change of the screen being wider, even when set at 100%.

Perhaps this is because 100% is in relation to the width difference of portrait to landscape. For example, this iPhone spec is 960 x 640. It may be that 100% means the inflation uses some direct relation of 960 x 640 (say, 960/640 x 100%), working out to be 1.5, which is then causing the "boldness" of the landscape text. If such is the case, then theoretically the -webkit-text-size-adjust would perhaps need to be set to 66.67% to keep it unaffected (returning the 1.5 factor to a 1). But I'm not convinced that it is so straight forward.

Ultimately, I think Andrey Bukati's answer of -webkit-text-size-adjust: none; is the only guarantee that no change in text sizing will occur. But it can have other, perhaps undesirable, affects.

Finding normal vector to iOS device

11 votes

I would like to use CMAttitude to know the vector normal to the glass of the iPad/iPhone's screen (relative to the ground). As such, I would get vectors like the following:

enter image description here

Notice that this is different from orientation, in that I don't care how the device is rotated about the z axis. So if I was holding the iPad above my head facing down, it would read (0,-1,0), and even as I spun it around above my head (like a helicopter), it would continue to read (0,-1,0):

enter image description here

I feel like this might be pretty easy, but as I am new to quaternions and don't fully understand the reference frame options for device motion, its been evading me all day.

  1. In your case we can say rotation of the device is equal to rotation of the device normal (rotation around the normal itself is just ignored like you specified it)
  2. CMAttitude which you can get via CMMotionManager.deviceMotion provides the rotation relative to a reference frame. Its properties quaternion, roation matrix and Euler angles are just different representations.
  3. The reference frame can be specified when you start device motion updates using CMMotionManager's startDeviceMotionUpdatesUsingReferenceFrame method. Until iOS 4 you had to use multiplyByInverseOfAttitude

Putting this together you just have to multiply the quaternion in the right way with the normal vector when the device lies face up on the table. Now we need this right way of quaternion multiplication that represents a rotation: According to Rotating vectors this is done by:

n = q * e * q' where q is the quaternion delivered by CMAttitude [w, (x, y, z)], q' is its conjugate [w, (-x, -y, -z)] and e is the quaternion representation of the face up normal [0, (0, 0, 1)]. Unfortunately Apple's CMQuaternion is struct and thus you need a small helper class.

Quaternion e = [[Quaterion alloc] initWithValues:0 y:0 z:1 w:0];
CMQuaterion cm = deviceMotion.attitude.quaternion;
Quaternion quat = [[Quaterion alloc] initWithValues:cm.x y:cm.y z:cm.z w: cm.w];
Quaternion quatConjugate = [[Quaterion alloc] initWithValues:-cm.x y:-cm.y z:-cm.z w: cm.w];
[quat multiplyWithRight:e];
[quat multiplyWithRight:quatConjugate];
// quat.x, .y, .z contain your normal

Quaternion.h:

@interface Quaternion : NSObject {
    double w;
    double x;
    double y;
    double z;
}

@property(readwrite, assign)double w;
@property(readwrite, assign)double x;
@property(readwrite, assign)double y;
@property(readwrite, assign)double z;

Quaternion.m:

- (Quaternion*) multiplyWithRight:(Quaternion*)q {
    double newW = w*q.w - x*q.x - y*q.y - z*q.z;
    double newX = w*q.x + x*q.w + y*q.z - z*q.y;
    double newY = w*q.y + y*q.w + z*q.x - x*q.z;
    double newZ = w*q.z + z*q.w + x*q.y - y*q.x;
    w = newW;
    x = newX;
    y = newY;
    z = newZ;
    // one multiplication won't denormalise but when multipling again and again 
    // we should assure that the result is normalised
    return self;
}

- (id) initWithValues:(double)w2 x:(double)x2 y:(double)y2 z:(double)z2 {
        if ((self = [super init])) {
            x = x2; y = y2; z = z2; w = w2;
        }
        return self;
}

I know quaternions are a bit weird at the beginning but once you have got an idea they are really brilliant. It helped me to imagine a quaternion as a rotation around the vector (x, y, z) and w is (cosine of) the angle.

If you need to do more with them take a look at cocoamath open source project. The classes Quaternion and its extension QuaternionOperations are a good starting point.

For the sake of completeness, yes you can do it with matrix muliplication as well:

n = M * e

But I would prefer the quaternion way it saves you all the trigonometric hassle and performs better.

UISlider highlight state with different thumb width than normal

10 votes

I'm trying to implement a custom UISlider (subclass of UISlider), that behaves in a similar way to the native slider that has a glow around the thumb when it's highlighted. I'm having trouble with this, though.

The (effective) width of the highlighted thumb is obviously greater than the normal thumb (due to the glow). If I add transparent pixel padding to the normal state image, so that both images have the same width, the issue is that the normal state thumb never looks like it reaches the end of the track (it does reach the end, but the padding makes it appear otherwise).

If I use thumbRectForBounds: to offset the thumb to line up correctly with the beginning of the track, it only makes the issue worse at the other end.

If I keep both images only as wide as they need to be (ie, no padding on the normal state, and the two are not the same width), I've gotten closer. I can set the offset independently in thumbRectForBounds: based on the UIControl.state, but it seems like the there's some math magic going on behind the scenes. The only place where the UISlider thinks the images for both states line up perfectly is the exact center.

It seems like I may need to implement some math that determines the offset of the highlight state based on it relative position along the track. It would need an y-offset of zero at the center (the UISlider would center both images, which means they align). At the extremes, it would need a y-offset that completely makes up for the glow. And in between it would need to interpolate the y-offset.

This seems like a lot of work to recreate something the native slider does though, so perhaps I'm missing something obvious.

Update Current solution:

It's not entirely portable, since it makes some assumptions about the size of the glow being added. I'm adding the glow with an image rather than drawing it directly to the CALayer. I haven't tested how performant this is yet.

Essentially I create a layer that's a square whose dimensions are the height of the default state thumb image, center it over the thumb, and then draw the glow (only the glow, not a separate image of a thumb with a glow, as would be done with a hightlight state image) into the layer.

- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
  CGRect r = [super thumbRectForBounds:bounds trackRect:rect value:value];

  [thumbHighlightOverlayLayer removeFromSuperlayer];
  thumbHighlightOverlayLayer = [CALayer layer]; 

  int x = r.origin.x + (r.size.width / 2) - (r.size.height / 2);
  thumbHighlightOverlayLayer.frame = CGRectMake(x, r.origin.y, r.size.height, r.size.height);

  UIImage* thumbHighlightOverlayImage = [UIImage imageNamed:@"thumb-highlight"];
  thumbHighlightOverlayLayer.contents = (id)thumbHighlightOverlayImage.CGImage;

  switch (self.state) {
    case UIControlStateHighlighted:
      [[self layer] addSublayer:thumbHighlightOverlayLayer];
      break;
    default:
      break;
  }

  return r;
}

instead of adding glow effect in the image, it may be better to add it dynamically. you can use CALayer to add glow effect.

CALayer

UIWebView and keep-alive?

10 votes

I am setting up an UIWebView to show the contents of a web camera through a URL that retrieves an MPJEG-stream.

I found out that if I wanted to switch to a different camera, it looked smoother if I did not reset the entire contents of the UIWebView, but instead set up a javascript function in the page I loaded into it, to replace the contents of the image, like this:

<img id='iImage' src='about:blank'>
<script type='text/javascript'>
function show(url)
{
    iImage.src = url;
}
</script>

If I did not do this, every time I switched to a new url, the UIWebView went white for a second or two until the new content was ready to be displayed, with the above code it just replaces the contents directly, no whiteout.

However, if I switch back and forth between two videostreams, at some point I get an error in the UIWebView, and by trial and error I've found out that this happens the 4th time I show the same videostream in the view. If I try to open up 4 videostreams in browser-tabs, the 4th get stuck in a loading cycle, until I close one of the previous three.

This leads me to believe that:

  1. The camera in question can only serve 3 streams at the same time
  2. Changing the src attribute on the <img...> tag does not close the previous stream

Can this be linked to keepalive? Could the webkit browser system keep the previous streams alive, even though I have stopped showing them in the <img...> tag?

Basically, to reproduce I can do this:

  1. Set up the above content in a UIWebView
  2. Call this 4 times: wv.EvaluateJavascript("show(url)")

On the 4th call, I get a blue question mark in the middle.

Can keep-alive be the culprit? And if so, can I control it?

This is being caused by WebKit not stopping loading of an image resource even if the source is changed. This normally doesn't cause a problem for images but a never-ending streaming image will cause it to never let go until the page is reloaded.

There is a bug filed against Chromium that points at this issue. https://code.google.com/p/chromium/issues/detail?id=73395

From the comment thread, a workaround is to call window.stop() before changing the image. This is the same as clicking stop in the browser and causes all loading resources to abort. Hopefully, the fact that this isn't causing the page to reload will avoid your white flash.

I'd give the following a try:

<img id='iImage' src='about:blank'>
<script type='text/javascript'>
function show(url)
{
    window.stop();
    iImage.src = url;
}
</script>

Implementing Fast and Efficient Core Data Import on iOS 5

10 votes

Question: How do I get my child context to see changes persisted on the parent context so that they trigger my NSFetchedResultsController to update the UI?

Here's the setup:

You've got an app that downloads and adds lots of XML data (about 2 million records, each roughly the size of a normal paragraph of text) The .sqlite file becomes about 500 MB in size. Adding this content into Core Data takes time, but you want the user to be able to use the app while the data loads into the data store incrementally. It's got to be invisible and imperceptible to the user that large amounts of data are being moved around, so no hangs, no jitters: scrolls like butter. Still, the app is more useful, the more data is added to it, so we can't wait forever for the data to be added to the Core Data store. In code this means I'd really like to avoid code like this in the import code:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];

The app is iOS 5 only so the slowest device it needs to support is an iPhone 3GS.

Here are the resources I've used so far to develop my current solution:

Apple's Core Data Programming Guide: Efficiently Importing Data

  • Use Autorelease Pools to keep the memory down
  • Relationships Cost. Import flat, then patch up relationships at the end
  • Don't query if you can help it, it slows things down in an O(n^2) manner
  • Import in Batches: save, reset, drain and repeat
  • Turn off the Undo Manager on import

iDeveloper TV - Core Data Performance

  • Use 3 Contexts: Master, Main and Confinement context types

iDeveloper TV - Core Data for Mac, iPhone & iPad Update

  • Running saves on other queues with performBlock makes things fast.
  • Encryption slows things down, turn it off if you can.

Importing and Displaying Large Data Sets in Core Data by Marcus Zarra

  • You can slow down the import by giving time to the current run loop, so things feel smooth to the user.
  • Sample Code proves that it is possible to do large imports and keep the UI responsive, but not as fast as with 3 contexts and async saving to disk.

My Current Solution

I've got 3 instances of NSManagedObjectContext:

masterManagedObjectContext - This is the context that has the NSPersistentStoreCoordinator and is responsible for saving to disk. I do this so my saves can be asynchronous and therefore very fast. I create it on launch like this:

masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[masterManagedObjectContext setPersistentStoreCoordinator:coordinator];

mainManagedObjectContext - This is the context the UI uses everywhere. It is a child of the masterManagedObjectContext. I create it like this:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[mainManagedObjectContext setUndoManager:nil];
[mainManagedObjectContext setParentContext:masterManagedObjectContext];

backgroundContext - This context is created in my NSOperation subclass that is responsible for importing the XML data into Core Data. I create it in the operation's main method and link it to the master context there.

backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundContext setUndoManager:nil];
[backgroundContext setParentContext:masterManagedObjectContext];

This actually works very, VERY fast. Just by doing this 3 context setup I was able to improve my import speed by over 10x! Honestly, this is hard to believe. (This basic design should be part of the standard Core Data template...)

During the import process I save 2 different ways. Every 1000 items I save on the background context:

BOOL saveSuccess = [backgroundContext save:&error];

Then at the end of the import process, I save on the master/parent context which, ostensibly, pushes modifications out to the other child contexts including the main context:

[masterManagedObjectContext performBlock:^{
   NSError *parentContextError = nil;
   BOOL parentContextSaveSuccess = [masterManagedObjectContext save:&parentContextError];
}];

Problem: The problem is that my UI will not update until I reload the view.

I have a simple UIViewController with a UITableView that is being fed data using a NSFetchedResultsController. When the Import process completes, the NSFetchedResultsController see's no changes from the parent/master context and so the UI doesn't automatically update like I'm used to seeing. If I pop the UIViewController off the stack and load it again all the data is there.

Question: How do I get my child context to see changes persisted on the parent context so that they trigger my NSFetchedResultsController to update the UI?

I have tried the following which just hangs the app:

- (void)saveMasterContext {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];    
    [notificationCenter addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];

    NSError *error = nil;
    BOOL saveSuccess = [masterManagedObjectContext save:&error];

    [notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
}

- (void)contextChanged:(NSNotification*)notification
{
    if ([notification object] == mainManagedObjectContext) return;

    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
        return;
    }

    [mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

You should probably save the master MOC in strides as well. No sense having that MOC wait until the end to save. It has its own thread, and it will help keep memory down as well.

You wrote:

Then at the end of the import process, I save on the master/parent context which, ostensibly, pushes modifications out to the other child contexts including the main context:

In your configuration, you have two children (the main MOC and the background MOC), both parented to the "master."

When you save on a child, it pushes the changes up into the parent. Other children of that MOC will see the data the next time they perform a fetch... they are not explicitly notified.

So, when BG saves, its data is pushed to MASTER. Note, however, that none of this data is on disk until MASTER saves. Furthermore, any new items will not get permanent IDs until the MASTER saves to disk.

In your scenario, you are pulling the data into the MAIN MOC by merging from the MASTER save during the DidSave notification.

That should work, so I'm curious as to where it is "hung." I will note, that you are not running on the main MOC thread in the canonical way (at least not for iOS 5).

Also, you probably only are interested in merging changes from the master MOC (though your registration looks like it is only for that anyway). If I were to use the update-on-did-save-notification, I'd do this...

- (void)contextChanged:(NSNotification*)notification {
    // Only interested in merging from master into main.
    if ([notification object] != masterManagedObjectContext) return;

    [mainManagedObjectContext performBlockAndWait:^{
        [mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];

        // NOTE: our MOC should not be updated, but we need to reload the data as well
    }];
}

Now, for what may be your real issue regarding the hang... you show two different calls to save on the master. the first is well protected in its own performBlock, but the second is not (though you may be calling saveMasterContext in a performBlock...

However, I'd also change this code...

- (void)saveMasterContext {
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];    
    [notificationCenter addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];

    // Make sure the master runs in it's own thread...
    [masterManagedObjectContext performBlock:^{
        NSError *error = nil;
        BOOL saveSuccess = [masterManagedObjectContext save:&error];
        // Handle error...
        [notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
    }];
}

However, note that the MAIN is a child of MASTER. So, it should not have to merge the changes. Instead, just watch for the DidSave on the master, and just refetch! The data is sitting in your parent already, just waiting for you to ask for it. That's one of the benefits of having the data in the parent in the first place.

Another alternative to consider (and I'd be interested to hear about your results -- that's a lot of data)...

Instead of making the background MOC a child of the MASTER, make it a child of the MAIN.

Get this. Every time the BG saves, it automatically gets pushed into the MAIN. Now, the MAIN has to call save, and then the master has to call save, but all those are doing is moving pointers... until the master saves to disk.

The beauty of that method is that the data goes from the background MOC straight into your applications MOC (then passes through to get saved).

There is some penalty for the pass-through, but all the heavy lifting gets done in the MASTER when it hits the disk. And if you kick those saves on the master with performBlock, then main thread just sends off the request, and returns immediately.

Please let me know how it goes!

MonoTouch v. Objective-C for new iPhone devs

10 votes

I'm working with a small startup with the goal of creating an iPhone application. The programmers on our team all know both C and Java, but we've got no ObjC/C#/iPhone experience -- we'll be learning something no matter what. All the questions I've seen on this subject have been from the perspective of a C# programmer getting into iOS, so I don't have any information on the relative merits of learning one or the other.

So, what I want to know is the relative merits of C# and Objective-C for new programmers, with respect to these things:

  • Performance
  • Ease of use
  • Ease of learning
  • Reliability (i.e., will a new iOS version break a MonoTouch app?)

Also, would writing in MonoTouch have any benefits for cross-platform development with Android?

If the goal of your startup is to create an iPhone app, then obviously you should learn the language iOS applications are built with, Objective-C. Your team already has experience with C, so it should be very easy to get started. The Big Nerd Ranch books will get you up and running in a week or two (I'm not associated with Big Nerd Ranch, I just think they're awesome).

I don't understand why you bring up MonoTouch, considering your team doesn't have C#/.NET experience. There are tons of other frameworks like MonoTouch, including Titanium SDK (JavaScript), RubyMotion (Ruby), and so forth. All of these are great, but as I see it are primarily for those with experience with their respective languages. They allow you to write iOS applications using a language you're more familiar with, but have the following drawbacks:

  1. Performance can be just as good, but usually a little (sometimes a lot) worse than an application written in Objective-C.
  2. Resources for learning are not as plentiful as those for iOS SDK/Objective-C. There are tons of people who want to make iOS apps, and of those people some use these frameworks, and they are diluted amongst them. Only a small fraction of the resources available for iOS development will be devoted to any given framework.
  3. These frameworks are based on the iOS SDK/Objective-C, so naturally development is always a step behind. If Apple rolls out radically new APIs in the next version of the iOS SDK, you'll have to wait for these frameworks to adapt (applications written in Objective-C might break, too, but it'll be easier to deal with based on point #2).
  4. Most of these frameworks require a familiarity with the iOS SDK. You will still need to know that an application calls the - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method on launch, but in addition you will need to remember how to translate that into the appropriate method for MonoTouch: public override bool FinishedLaunching (UIApplication app, NSDictionary options). The iOS SDK is massive, and most iOS developers rely on Apple's documentation for insight. So you will be looking at the API docs, written for Objective-C, and translating methods into the framework of your choice.
  5. The Objective-C ecosystem is constantly evolving, with cool new projects like CocoaPods, bwoken, etc. These are primarily developed with Objective-C and Xcode in mind. Configuring them to work with your framework of choice will almost invariably cause you extra time and work.

The above points have generally kept me from delving too much into any of these other frameworks. They're all very cool, but their primary merit in adoption seems to be facilitating development for people with deep skill sets outside of Objective-C, or allowing cross-platform development for small teams lacking the resources to invest in Android and iOS (and Windows Phone) programmers. Hopefully the benefits outweigh the above costs for adopters.

Also, would writing in MonoTouch have any benefits for cross-platform development with Android?

I suppose it would. Indeed, the MonoTouch homepage touts that as a primary advantage of using the framework. I'm not so sure about view/controller classes, since those seem like they would be tied into UIKit, but the logic encapsulated in your models should be fairly easy to port.

Long story short, I think you and your team should stick with Objective-C for iOS development.

NSString by removing the initial zeros?

9 votes

How can I remove leading zeros from an NSString?

e.g. I have:

NSString *myString;

with values such as @"0002060", @"00236" and @"21456".

I want to remove any leading zeros if they occur:

e.g. Convert the previous to @"2060", @"236" and @"21456".

Thanks.

NSString *str = @"000123";      
NSString *clean = [NSString stringWithFormat:@"%d", [str intValue]];

ALAssetsLibrary - crash after receiving ALAssetsLibraryChangedNotification

9 votes

Part of my app has a photo browser, somewhat similar to Apple's Photos app, with an initial view controller to browse photo thumbnails and a detail view that's shown when you tap on a photo.

I'm using ALAssetsLibrary to access photos, and I pass an array of ALAsset URL's to my detail view controller so you can swipe from one photo to the next.

Everything works great, until I receive an ALAssetsLibraryChangedNotification while swiping from one photo to another (in the detail view controller), which often results in a crash:

NOTIFICATION: the asset library changed // my own NSLog for when the notification occurs

loading assets... // my own NSLog for when I start reloading assets in the thumbnail browser

Assertion failed: (size == bytesRead), function -[ALAssetRepresentation _imageData], file /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m, line 224.

The specific line of code it crashes on, is in calling [currentRep metadata] as shown here:

- (void)someMethod {
        NSURL *assetURL = [self.assetURLsArray objectAtIndex:index];
        ALAsset *currentAsset;

        [self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {

            [self performSelectorInBackground:@selector(configureDetailViewForAsset:) withObject:asset];

            } failureBlock:^(NSError *error) {
                    NSLog(@"failed to retrieve asset: %@", error);
        }];
}

- (void)configureDetailViewForAsset:(ALAsset *)currentAsset {
    ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation];

    if (currentAsset != nil) {
        // do some stuff
    }
    else {
        NSLog(@"ERROR: currentAsset is nil");
    }

    NSDictionary *metaDictionary;
    if (currentRep != nil) {
        metaDictionary = [currentRep metadata];

        // do some other stuff
    }
    else {
        NSLog(@"ERROR: currentRep is nil");
    }
}

I understand that once a notification is received, it invalidates any references to ALAsset and ALAssetRepresentation objects... but how am I supposed to deal with the situation where it invalidates something right in the middle of trying to access it?

I've tried setting a BOOL, right when receiving the notification to completely abort and prevent [currentRep metadata] from ever being called, but even that doesn't catch it every time:

if (self.receivedLibraryChangeNotification) {
    NSLog(@"received library change notification, need to abort");
}
else {
    metaDictionary = [currentRep metadata];
}

Is there anything I can do? At this point I'm almost ready to give up on using the ALAssetsLibrary framework.

(note this unresolved thread on the Apple dev forums describing the same issue: https://devforums.apple.com/message/604430 )

It seems the problem is around here:

[self.assetsLibrary assetForURL:nextURL 

    resultBlock:^(ALAsset *asset) {
        // You should do some stuff with asset at this scope
        ALAssetRepresentation *currentRep = [asset defaultRepresentation];
        // Assume we have a property for that
        self.assetRepresentationMetadata = [currentRep metadata];
        ...
        // assume we have a method for that
        [self updateAssetDetailsView];
    } 

    failureBlock:^(NSError *error) {
        NSLog(@"failed to retrieve asset: %@", error);
    }];

Once you have got user asset it is better to copy asset information by providing necessary data to your details controller subviews or by caching for later use. It can be helpful for avoiding ALAsset invalidation troubles. When notification ALAssetsLibraryChangedNotification sent you may need to discard details controller and query the Library content from the beginning.

iOS and ARC : How to retain self during asynchronous operations?

8 votes

It's the first time I'm fiddling around with iOS5 and ARC. So far, so good, it works, but I've run into some kind of a problem.

I have a custom UIStoryboardSegue in which I use Facebook Connect (or other services) to log the user into my app. Simply put, it should do the following :

  1. User clicks on the button
  2. Button fires the Segue
  3. The segue starts asynchronous login but does not immediately push the view controller
  4. If, and only if the login is successful, the segue pushes the view controller

What happens instead, is that the login starts, but the segue is immediately released by ARC before it has any chance to complete.

I thought of a quick'n'dirty hack to prevent this:

@interface BSLoginSegue() {
    __strong BSLoginSegue *_retained_self;
}
@end

// Stuff...
// Other stuff...

- (void) perform {
    login();
    _retained_self = self;
}

- (void) loginServiceDidSucceed:(BSLoginService *)svc {
    ...
    _retained_self = nil;
}

The thing is, it really is a hack, so I was wondering if there were any other, and more elegant way I could do the same?

The idea that a class should need to retain itself suggests that there might be a design problem. When an object retains itself, it becomes unclear who owns it or who might have a reference to it, and the risk of a leak is high.

What class is responsible for presenting the segue? Is it the same class the contains the button? This class should retain the segue, present the segue, and then release the segue when/if the segue completes.

Without further insight into the view controller hierarchy, it's hard to give specific advice. But my first reaction is to suggest that the view controller that is deciding to present the segue or not should have a strong property on the segue. The subclassed segue might define a protocol that the presenting class may conform to to be advised as to when the segue should be nilled/released.

How to send files to other iPhones via Bluetooth

8 votes

I'm doing a little app to allow users to edit and share text fast on the iPhone.

So I know a little of Bluetooth programing for iPhone, but I'm not able to do what I want to do:

  • The text of the app is saved in NSUserDefaults. I want to send this to another iOS device by the key: "Text1", "Text2" or "Text3"( I know that I have to convert the text that will be in a string to NSData, and tren I would like to have it in a NSMutableDictionary with its key)

  • I also want to be looking for new iOS devices arround all the time.

Please help me because I don't know how I can do it and it's so hard to find tutorials of iPhone Bluetooth programming, thank you!

Use GameKit, there are many tutorials.

Use this to find other devices:

GKPeerPickerController *picker = [[GKPeerPickerController alloc] init];
picker.delegate = self;
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[picker show];

How to transport NSManagedObject subclass between classes?

8 votes

We have made a repository layer for interacting with Core Data that have methods such as allItems(), addItem:(Item*)item where item being the NSManagedObject subclass. When we need to save an item we invoke the method on the repository passing the subclass instance as an argument. However, that does not work because we can't use the initinitializer and the context is hidden inside the repository.

What is the best way to transfer objects when you have an architecture like this? Is making a ItemDTO an passing that around an option? Or are there better ways to solve this such as not using subclassed NSManagedObject at all and just use key/value that works.

I wrotecopy-pasted a sample project that hides the context from model custom classes: branch 10583736.

(it's not final production code, just a quick example, don't expect it to deal with multithreading or weird errors)

Hiding the context to custom classes is just a matter of defining custom methods to deal with every situation where you normally will request the context and use it.

You can define a class for the store layer without exposing the context:

@interface DataStore : NSObject

+ (id)shared;

- (void)saveAll;
- (NSEntityDescription *)entityNamed:(NSString *)name;
/* more custom methods ... */
- (NSManagedObject *)fetchEntity:(NSEntityDescription *)entity withPredicate:(NSPredicate *)predicate;

@end

I suggest to use a common ancestor for all your custom model classes to save some typing. This class can be the only one that interacts with DataStore directly. It doesn't have access to the context.

@interface DataObject : NSManagedObject

+ (NSString *)entityName;
+ (NSEntityDescription *)entity;
- (void)save;
/* more custom methods ... */

@end

Finally your model custom classes defines any method you need probably taking advantage of whatever is provided by the superclass:

@interface Card : DataObject

@property (nonatomic, retain) NSString * question;
@property (nonatomic, retain) NSString * answer;
@property (nonatomic, retain) Deck *deck;

/* return a new card */
+ (Card *)card; 

/* more custom methods ... */

@end

The master branch has a more usual approach where model classes obtain the context and work with it.

How to do 'serial' animation with GCD?

8 votes

I'm trying to make a custom UIView displays on screen for 5s when a remote notification comes.

Code like this:

//customView.alpha = 1.0 here
[UIView animateWithDuration:1 animations:^{
                                  customView.alpha = 0.3;
                              } 
                              completion:^(BOOL finished){
                                  // remove customView from super view.
                              }];

Problem and What I Need

But there're cases that a couple of notification may come at short time interval, in which several customView may be animating at the same time and one may cover others.

I want these animations perform one after another, so that they won't conflict.

Assumed but Failed

//(dispatch_queue_t)queue was created in other parts of the code
dispatch_sync(queue, ^{
    [UIView animationWithDuration:animations:...];
});

After making the animation in GCD queue, I got the same result as the origin code I used, which didn't use GCD. Animations are still conflicting.

BTW, I heard that animations or tasks involving UI should always be run on main thread, but in my second code the animation seemed done smoothy. Why?

If it's the same animation that runs every time then you could just have store the number of times that the animation should run (not the same as the repeat count property of the animation).

When you receive the remote notification you increment the counter and call the method that animates if the counter is exactly one. Then in the methodThatAnimates you recursively call yourself in the completion block while decreasing the counter every time. It would look something like this (with pseudocode method names):

- (void)methodThatIsRunWhenTheNotificationIsReceived {
    // Do other stuff here I assume...
    self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation + 1;
    if ([self.numberOfTimesToRunAnimation == 1]) {
        [self methodThatAnimates];
    }
}

- (void)methodThatAnimates {
    if (self.numberOfTimesToRunAnimation > 0) {
        // Animation preparations ...
        [UIView animateWithDuration:1 
                         animations:^{
                                  customView.alpha = 0.3;
                         } 
                         completion:^(BOOL finished){
                                  // Animation clean up ...
                                  self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation - 1;
                                  [self methodThatAnimates];
                         }];
    }
}

Can the messages sent to an object in Objective-C be monitored or printed out?

7 votes

Possible Duplicate:
Intercept method call in Objective-C
How to log all methods used in iOS app

For example, a UIViewController object in iOS receives many messages before its view is shown to a user:

  1. viewWillAppear
  2. viewWillLayoutSubviews
  3. viewDidLayoutSubviews
  4. viewDidAppear
  5. ...

because the framework's source code is not viewable, we have to rely on books or blogs, or is there a way to print out or monitor all the messages sent to this object by (1) Objective-C, or (2) by any tool?

Rather than my comment, the best approach that I used (and still use) is calling:

(void)instrumentObjcMessageSends(YES);

When I need to start logging all messages and then:

(void)instrumentObjcMessageSends(NO);

Don't forget to add #import <objc/runtime.h>.
When I don't need it anymore. The annoying thing is that the log is created under /tmp/msgSends- and this means that you have to open the terminal and use tail to see it in a readable way.

What is printed is something like this:

- CustomTableViewController UIViewController _parentModalViewController
- CustomTableViewController UIViewController isPerformingModalTransition
- CustomTableViewController UIViewController setInAnimatedVCTransition:
- CustomTableViewController UIViewController viewWillMoveToWindow:
- CustomTableViewController UIViewController isPerformingModalTransition
- CustomTableViewController UIViewController parentViewController
- CustomTableViewController UIViewController _popoverController
- CustomTableViewController UIViewController _didSelfOrAncestorBeginAppearanceTransition
- CustomTableViewController UIViewController parentViewController
- CustomTableViewController UIViewController __viewWillDisappear:
- CustomTableViewController UIViewController _setViewAppearState:isAnimating:
- CustomTableViewController UIViewController automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers

Note: It has been a while since I used this approach for the last time and it looks like this approach doesn't log private methods subclassed. So, if you have a DummyClass with -(void)_dummyMethod as private and then a DummySubClass with a -(void)_dummyMethod implementation, the message will not be logged.

For iOS, this works only on Simulator.