Best iphone 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 restrict any developer from using my created static library?

9 votes

I have created one static library in iPhone sdk, and I am worried that If I provide code to anyone inwhich static libray is being used, then anyone can use static library. So Is there any way to restrict them by using library until they get license? I am new to licensing any library.

This is a problem you must solve by legal means, not by any technical solution.

Make sure to only give the library to people you trust, and if needed have them sign an agreement not to spread it.

Also ask yourself if it is worth the trouble. Is your code so unique that they can not find it elsewhere, or duplicate it themselves in a few days, using Google and stackoverflow alone?

Localize iPhone App name in Xcode 4

9 votes

When I select the Info.plist file so that the App name can be localized and try to build the project, the build fails with an error saying that the Info.plist file cannot be found.

If I change the Info.plist file path to PROJECTNAME/en.lproj/Info.plist it builds, but the App's name is not localized; if I run on a Portugues iPhone it has the English name.

Why?

Thanks,

RL

Add InfoPlist.strings to your project and localize it. Put this in different languages:

"CFBundleDisplayName" = "App Name";

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.

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 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.

for loops - Object type disregarded?

6 votes

I sometimes like to organize IB elements into NSArrays primarily to help me organize my elements. Most often, different classes of objects make it into the same array with each other. While this is a convenient way of organization, I can't seem to wrap my head around why if I have an array like this:

NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil];

Why I get "Does not respond to selector" messages when I put a for loop like this:

for (UITextField *text in array) {
    [text setText:@""];
}

The for loop seems to be passed objects that are not of class UITextField.

What is the point of declaring the object's class if all objects in the specified array are passed through the loop?

EDIT Just for reference, this is how I'm handling it as of now:

for (id *object in array) {
    if ([object isMemberOfClass:[UITextField class]]) {
        foo();
    } else if ([object isMemberOfClass:[UISegmentedController class]) {
        bar();
    }
 }

When you do

for (UITextField *text in...

the object pointers from the array are cast to UITextField* type - so if the object isn't actually a UITextField, all sorts of weird things may happen if you try to call UITextField methods.

So instead use the id type (no * needed, btw):

for (id obj in array)

Then check the type as you do and call the appropriate methods. Or, filter the array to get only objects of a certain type, then go though that type only:

for (UITextField* text in [array filteredArrayUsingPredicate:...])

Edit: here's how to build class filter predicates:

Is it possible to filter an NSArray by class?

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.

Is QT available for android and iphone platforms?

6 votes

Is QT available for the android and iphone platforms?

I want to develop a single code base for these two platforms - can it be done?

  • If yes, what tools do I need? (a link to a tutorial would be great)
  • If no, why not? (what are the obstacles, and how may they be overcome - i.e. workarounds?)

There is experimental Qt support for Android.

http://sourceforge.net/p/necessitas/home/necessitas/

See this question for iPhone. Qt for iPhone/iPad?