Best ios questions in August 2011

UIDevice uniqueIdentifier Deprecated - What To Do Now?

13 votes

It has just come to light that Apple have deprecated the UIDevice uniqueIdentifier property with iOS 5 and above. No alternative method or property appears to be available or forthcoming.

Many of our existing apps are tightly dependant on this property for uniquely identifying a particular device. Can anyone suggest any ideas how we might handle this problem going forward?

The suggestion from the documentation is...

Special Considerations

Do not use the uniqueIdentifier property. To create a unique identifier specific to your app, you can call the CFUUIDCreate function to create a UUID, and write it to the defaults database using the NSUserDefaults class.

... however this value won't be the same if a user uninstalls and re-installs the app.

A UUID created by CFUUIDCreate is unique if a user uninstalls and re-installs the app: you will get a new one each time.

But you might want it to be not unique, i. e. it should stay the same when the user uninstalls and re-installs the app. This requires a bit of effort, since the most reliable per-device-identifier seems to be the MAC address. You could query the MAC and use that as UUID.

Edit: One needs to always query the MAC of the same interface, of course. I guess the best bet is with en0. The MAC is always present, even if the interface has no IP/is down.

How can I track down memory peaks? (That's peaks with a p, not an l.)

9 votes

I've got a kiosk app, which, essentially shows a bunch of slides with various bits of information on them. I initially began coding this over a year ago, when I was beginning with Objective-C and iOS development. I find that my code style is much cleaner now than what it was, and I'm much more experienced, so I've decided to rewrite from scratch.

I ran my app with the Allocations instrument to see what the memory usage was. Considering that this is a kiosk app, everything needs to run smoothly, without leaks. (Of course all apps need to run without leaks, but a kiosk app makes this an even more important goal.) I saw some interesting results, so I ran the old version of the code as well.

Running the older version of the code, I see a pretty much even run at about 1.15 megabytes of memory usage. Everything seems to be allocated and deallocated as necessary. In my new implementation, however, I'm seeing something a little different. Memory usage keeps jumping in little "plateaus", and then eventually seems to peak out at about 1.47 megabytes of usage. Here's what the new Allocations report looks like after running for over 10 hours:

enter image description here

I'm concerned for several reason.

  1. The odd pattern in the beginning of the run.
  2. Allocations seems to peak at 1.47 megabytes, but running it overnight shows that it actually will slowly use more and more memory over time. That can't be a good thing.

There are several notable differences between the old project and the new one.

  • The older one uses Plists as a backing store (I manually read and write to a plist file.) The new project uses Core Data.

  • The new project implements a library that is called on each "slide" that the old project didn't have. I'd be more concerned about this library, except I wrote it and I went through it to make sure I was releasing everything and only autoreleased wherever manual releases were impossible.

  • Both classes use a factory class to create the slides. In the old project, the factory class was a singleton. I thought that making it into a normal class would help with the memory issues, since the singleton was never released. (Hence it's properties were not being released.In the new project, the factory class is being released so I'm not sure why it's still taking up all that memory (if that's what's causing the problem.

  • The old project makes use of string constants in various places. The new code uses a massive enum for the same thing. (The new code in general uses more constants.)

What can I do to track down memory peaks? The memory is all being cleaned up by the application when it discards whatever it's using, but it doesn't seem to be discarding things until the app terminates.

I'd be grateful if anyone would help point me in the right direction.

Edit:

It looks like the peaking is being caused by calls to the KosherCocoa library. If anyone would mind taking a look at it and telling me what I'm doing wrong there as far as memory management goes, I'd really appreciate it.

What can I do to track down memory peaks? The memory is all being cleaned up by the application when it discards whatever it's using, but it doesn't seem to be discarding things.

This is a classic case of "abandoned objects" or "usage accretion". That is, you have an application that, as it runs, builds up an object graph in memory as a normal part of usage. The objects aren't leaked because they are still connected to the live object graph. More likely than not, the objects are a part of either some kind of a cache (a write-only cache, most often) or a mechanism involving historical state (the undo stack is a potential source for accretion).

To fix it, you need to make sure your object graph is pruned appropriately as your app runs. Caches should generally use a least-recently-used [LRU] pruning algorithm that limits the cache size. If a cache key ever goes invalid, that data should be pruned, too.

For historical information, pruning the history is critical. So is making sure that the historical data contains an absolutely minimal representation of that historical state.

Use Heapshot analysis -- it was created to help track down exactly these kinds of problems.

I wrote a detailed "How to" guide; When is a Leak not a Leak?

Is it too soon to use Couchbase Mobile?

8 votes

For an iPhone App I decided to give a try to a NoSQL DB, because the nature of the data I need to store locally. The most sophisticated solution I found is Couchbase Mobile. But it seems, that the project has only beta status. Is it too soon to use it?

Couchbase Mobile is currently beta, with plans for a GA/1.0 at the end of September (2011).

By the next developer preview release at the end of August the iOS version should be entirely ready for you to start development with. The Android version is lagging a little in terms of documentation, but should also be ready for active development at the end of August.

If you are hard core, you can start today, but if you wait a few weeks we'll be ready for even the non-hardcore.

How to protect app IPA from hacks if reverse engineering is possible

7 votes

Recently we developed and published a mobile banking app on the app store, for a big banking organization. The bank hired a security firm to perform ethical hacking over the app to see if it, in anyways compromises confidential data.

We recently received the hacking report from the firm, which in-spite of saying that no serious security issues are present, contains a list of all the class files, method names and the assembly code of the project.

Now the client insists that we fix these security loop holes and republish the app. However we don't have any idea how did they manage to get all these details from the application's IPA. I searched this over SO and found a particular post mentioning this link, which states that you can't save your app from being hacked.

Please help me how to fix these security vulnerabilities , or if not possible, how to convince the client.

There's always a risk involved. Even if you don't introduce vulnerabilities yourself, the platform may allow for exploits which in the end may offer an entry point for a malicious attacker.

As to your question: It is not safe to assume that a hardcoded URL, even if obfuscated beyond belief, can't be peeled out of your product. Always design your apps such that safety of user data is guaranteed (as far as possible) even if built in ressources get compromised. If the knowledge of that URL alone poses a security threat, then your whole approach and your clients API is inherently insecure. Remember that such information could possibly be captured by a man-in-the-middle attack (and other modes of attack) as well.

Avoid security by obscurity. Store sensitive data only on disk if it is necessary. As a rule don't allow PIN / TAN storage.

Some thoughts which may (or may not) convince your client that your app is as safe as it can be:

  • As long as the app runs on a non-jailbroken device, it is unlikely that an attacker, even with knowledge of your apps internals is able to get to any user data, because the iPhone normally doesn't offer opportunities to interfer with your app
  • If the attacker is able to get to your users data, and provided you have been protecting that data with all means available under iOS (-> keychain -> crypto chip ->...), then it's not your fault. It means the device is either jailbroken or there are vulnerabilities to the system itself which have been exploited, you just can't do anything about either possibility.
  • It is impossible to prevent reverse engineering of your app. Even if you had put more effort into obfuscation, an attacker with strong motivation would still be able to get what he wants. Your client needs to get used to this as it's a fact.
  • Other platforms suffer from similar vulnerabilities, yet on the iPhone at least you have a somewhat closed environment and a reduced risk of being attacked with trojans and the like.
  • The governments and security firms get hacked on a regular basis, although they should now how to protect themselves. This means life is inherently insecure, cope with it.

iOS Core Animation - Fold a Layer

7 votes

Using Core Animation, I would like to fold a UIView (i.e. it's CALayer) on it's center. i.e. I would set the anchor point as (0.5,0.5) & fold the layer. This image that I created in Photoshop might give the effect I am looking for -

enter image description here

So, what's happening is, the layer is being folded on its center, as the fold is happening a little bit of perspective is applied (the infamous m34!). Initially, the view is parallel in X-Y plane with Z axis looking straight to the user. As the fold is happening, bottom half & top half at the same time move back (with some perspective, to give depth & 3D effect) till the entire layer is (parallel) in X-Z plane. Note that once the layer is parallel in X-Z plane, the user will no longer be able to see the Layer. But that's ok, that's the effect I am looking for. A UIView disappearing by folding on it's center.

How would one go about doing this in iOS? Without using 2 different layers (for bottom & for top)? Any help is much appreciated...

Update: As @miamk points out, this is the same UI effect used in "Our Choice" App or "Flipboard" App. I am wacking my brains out for the last 8 hours on this, so far fruitless. ANY idea is appreciated. Thanks...

UPDATE: I have offered bounty on this to get more specific answers. Would love to see -

  1. Code samples.
  2. Advise from people who have done something like this.
  3. Even the way to achieve this in a detailed fashion (algo) is much appreciated.

A CALayer is a plane, and can not be folded. Unless you write a core image filter for it, like the page curl effect, but that if private API and not an option to you.

You need to split your view into two views, and fake the fold by transforming the two CALayers simultaneously.

By default a layers transform do not have perspective, so you must also setup this:

 transform.m34 = 1.0 / -2000;

OK Let's be even clearer: Split the view in two and fold them:

Your view hiarchy according to the image you posted looks something like this:

+ UIView      - Root view
    + UIImageView - The persons face
    + UILabel     - The label with title
    + UILabel     - The label with company name
    + UILabel     - The label with a short description.
    + UILabel     - The label with e-mail
    + UILabel     - The label with web address
    + UILabel     - The label with phone number

So introduce two new views to this view hierarchy for the purpose of folding, like this:

+ UIView    - Root view
    + UIView      - Top half of the card
        + UIImageView - The persons face
        + UILabel     - The label with title
        + UILabel     - The label with company name
        + UILabel     - The label with a short description.
    + UIView      - Bottom half of the view
        + UILabel     - The label with e-mail
        + UILabel     - The label with web address
        + UILabel     - The label with phone number

Not too hard. Now animate only the two views used for grouping the top and bottom half.

I will not write the code for you, but one more vital tip to make it easy: Change the anchor points of the view to animate! You do not want to rotate them by their own centers, instead shift the center of rotation to align with the edges they have against each other.

 topView.layer.anchorPoint = CGPointMake(0.5f, 1.0f);
 bottomView.layer.anchorPoint = CGPointMake(0.5f, 0.0f);

Adding Core Data to iPhone app with existing (plain) models

7 votes

I have a reasonably complex iPhone app that relies on an API to fetch data from a server and display it to the user. I have about 5 model classes that are used throughout the app - they simply extend NSObject.

I want to add some persistance to the models, to allow certain parts of the app to be used even if the device is offline - it really is basically just glorified caching. I only want certain instances of my models to be persisted - for example, items the user has bookmarked - and others should not, for example hundreds of search results.

Is Core Data the right solution for this? The difficulties I can see are:

  • I would have to change the way I instantiate my model objects throughout the project. I would have to initialize them as part of a context, which does not necessarily make sense if they're actually coming from an external API.
  • I would need to be careful not to persist instances I don't want. This seems to boil down to either deleting a Managed Object right after it's created (really awkward) or using a separate, non-persistent context for instances I don't want persisted (better, but still somewhat awkward)

I was hoping I could keep using my models throughout the app without changing the code that doesn't need to care about persistance, but that doesn't seem feasible given my requirements. The alternative is to set up a new set of Managed Objects in parallel to my existing objects, and only use the Managed Objects for persistance - but this kind of duplication never seems like the right solution.

Should I be trying to shoehorn Core Data into this, and if so, how? Or should I just be looking at other options - sqlite3 (seems a bit complicated for what I need), user defaults (probably not what they're intended for), or even serializing and writing my own objects to files (seems hack-ish).

Thanks for any input!

Why not take a look at NSKeyedArciver/Unarchiver? I would say that Core Data is the obvious solution when working with very large amounts of data along with sqlite databases, but NSKeyedArchiver is what I use to save models. Check out Apple's documentation here. Using NSKeyedArchiver is pretty simple IMO, and you can store pretty much anything you need with it.

How can I build a Mac package on linux? (BOM file problem)

7 votes

I'm running a business where we are creating email stationeries for people. We have some Mac users that currently have to download a zip file and manually copy that to their mail stationeries directory.

I want to automate that process and allow Mac users to download directly a package that will copy those files automatically.

I've build a sample package with PackageMaker, created script that will replace Archive.pax.gz with client's stationeries but go an error. I have realized I did not provide a mandatory BOM file. How can I create it on a non-mac platform? Or if I can't, is there any other way to create a Mac installer on a non-mac platform?

Finally I've created a postflight hook which is actually doing all the installation process

What is the recommended method of styling an iOS app?

7 votes

What is the recommended method of styling an iOS app? For example, if there are multiple labels or text views how can updating font style/color at one place update the style/color at all other places?

I know sub classing could be one way... is there any other way?

You could import a standard header file into all your controller's with several constants set for styling... example:

Styles.h

#define kFontSize 14
#define kFontFamily @"Helevetica"

Controller

#import "Styles.h" // at the top

myLabel.font = [UIFont fontWithName:kFontFamily size:kFontSize];

I personally think Interface Builder is the best way to style, however this answers your question directly.

How can I disable any CLRegion objects registered with -startMonitoringForRegion?

6 votes

I am using a NavigationController to display a list of geo-fences available to the user. At the top there is a global on/off switch that I would like to use to disable any fences registered with CoreLocation -startMonitoringForRegion.

My fences seem to be registering ok and working for the most part, but no matter how many times I disable the fences individually, I'm still getting the purple location arrow indicating that the system is still monitoring my location and/or fences.

When I disable my fences individually, this is how I'm doing it.

CLLocationCoordinate2D coord;
coord.latitude = [[settingsData valueForKey:@"latitude"] doubleValue];
coord.longitude = [[settingsData valueForKey:@"longitude"] doubleValue];
CLLocationDistance radius = [[settingsData valueForKey:@"radius"] intValue];
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coord radius:radius identifier:[settingsData valueForKey:@"name"]];

// remove this fence from system monitoring
[locationManager stopMonitoringForRegion:region];
[region release];

I've gone through all of Apple's documentation on CoreLocation and use of these methods and I'm at the end of my rope.

I've tried calling [locationManager monitoredRegions]; but it only returns the active fence and only when I have my detail view loaded up. I'm not able to call it any other place in my program and get it to return any of my fences, even though I know they should be active. If anyone has any advice where to go next, I'm all ears.

Ok, I think I can answer my own question here finally. Does this mean I can claim my own bounty? :D

First off, the lingering location arrow seems to be an iOS bug. I have found multiple stories out there with the very same issue. So there won't be much I can do about that for now.

As far as removing all of my regions at once, I got this down pat now.

NSArray *regionArray = [[locationManager monitoredRegions] allObjects]; // the all objects is the key
for (int i = 0; i < [regionArray count]; i++) { // loop through array of regions turning them off
     [locationManager stopMonitoringForRegion:[regionArray objectAtIndex:i]];
}

I was able to display my array and proved they were all in there. Another check after removing shows they are all gone. Whew!! The issue of the location arrow remains depending on which version of iOS you are running. I can't that I guess. If you have users, make sure you inform them the purple arrow is not your fault. For more info on the issue, you can start here. GetSatisfaction Good luck.

iOS: Mask a UIImage using UIBezierPath

6 votes

I am trying to mask an image so that I can give it only two rounded corners. With the code that I have it just adds the mask in white over the image, but doesn't seem to apply it. What do I need to do different to mask the image corners?

CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:maskLayer.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(16.f, 16.f)];    
maskLayer.fillColor = [[UIColor whiteColor] CGColor];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [roundedPath CGPath];

// Add mask
self.imageView.layer.mask = maskLayer;

Round two corners in UIView

As mentioned in the above linked question, you probably need to remove the view from the heirarchy before applying its mask.

[self.imageView removeFromSuperview];
self.imageView.layer.mask = maskLayer;
[self.view addSubview:self.imageView];

Also, your maskLayer has no bounds. You need to set it to the frame (or bounds) of the view you're trying to mask.

CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.imageView.frame;

JavaScript in iPhone programming

6 votes

I am currently developing apps for the iPhone and iPad with Objective-C. I found some code related to using JavaScript in the iPhone.

  1. Can we create apps more easily and accurately with the help of JavaScript?
  2. Does Apple approve apps created at least partially with JavaScript?
  3. How should one begin learning JavaScript?
  4. Are there any tutorials that can help me to understand and learn JavaScript, particularly for iPhone/iPad programming?

Web Apps

Web Apps are highly optimized special websites that are accessed from any device but still look and feel like a full-fledged application. An early example would be GMail. Here is an old blog post by jQuery's John Resig on early web app development.

1. Can we create apps more easily and accurately with the help of Javascript?

This is a bit mis-leading as the intents may be different. The goal of web apps to hit the widest possible audience with minimal effort, however, you are restricted to non-native functions.

Native functions include use of the device hardware such as camera, gps, touching other apps, notifications etc. There are several libraries that provide a wrapper around your web app to expose these underlying calls but then you must do that for each device. Libraries include: Phonegap, Titanium.

2. Does Apple approve apps created at least partially with JavaScript?

Most certainly! They even have a special section. With most webapps it is just a bookmarklet the user drags to their home screen for quick access. If you want to do the true app in the store you will need a wrapper library as mentioned before to package your app together.

3. How should one begin learning JavaScript?

Out of scope for this question, but Douglas Crockford is one of the better teachers, he has a multi-part video series as well as a book to get you learning the "good parts".

4. Are there any tutorials that can help me to understand and learn JavaScript, particularly for iPhone/iPad programming?

Honestly, it would best to learn javascript first, as it is a prototypical object based puzzle then worry about how to utilize the various frameworks for best mobile performance.

Adding 5. What are some javascript mobile frameworks?

These are just the most common but I would browse each of them a bit as jQuery, dojo and sencha have different approaches on how javascript should be used.

How to call a method a.s.a.p. but at earliest in the next run loop iteration?

6 votes

I need a save way to say: "iOS, I want this method to be executed a.s.a.p., but NOT in THIS run loop iteration. At the earliest in the next, but please not in this one. Thank you."

Right now I am always doing it like this:

[self performSelector:@selector(doSomethingInNextRunLoop) withObject:nil afterDelay:0];
[self doSomeOtherThings];

With the assumption that -doSomeOtherThings will always be performed BEFORE -doSomethingInNextRunLoop.

The documentation says:

Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread’s run loop and performed as soon as possible.

So basically it can happen that the method gets called immediately as if I had just sent a direct message, causing -doSomethingInNextRunLoop to be executed before -doSomeOtherThings?

How can I make absolutely sure it will be called a.s.a.p. but NEVER ever in this same run loop iteration?

To clarify the wording: With run loop I mean the main thread, and the iteration in which all methods must return until the thread is ready again for new events.

If you're worried that Apple may someday special-case a delay of 0, you could always specify a delay of 1e-37 or so. Although the documentation for performSelector:withObject:afterDelay: could easily be read to guarantee that the selector will always be scheduled for the next run loop iteration.

If you're worried that Apple may someday special-case delays less than some arbitrary lower bound, you could always try using NSRunLoop's performSelector:target:argument:order:modes: which the documentation specifically states will schedule execution for the next iteration of the run loop.

Know if iOS device has cellular data capabilities

6 votes

I have a toggle in my app that's "download on WiFi only". However, that toggle is useless for iPod touch or WiFi-iPads.

Is there a way to know if the device has cellular data capabilities in code? Something that would work in the future would be great too (like if an iPod touch 5th gen with 3G comes out).

This is not currently possible as of iOS 4.3.

I've filled an enhancement request.