I did not only enjoy vacation during winter holidays. I worked hard on Talerka iOS application and we did release a new version which supports iOS 7-look and also features side menu.
The good things about side menu that it allows you to use much more space for content:
more space on recipe screen – easier to read
More space on search screen gave as a possibility to increase the heigh of table’s rows; thus, it became easier to tap on them
The bad thing is that I’ve broken (unintentionally) a iOS5 support. The update is on the way – after it becomes available the application will support all iOS vesrions from 5.0 to 7.0.
As you know, we have to use ABAddressBookRequestAccessWithCompletion call in order to get access to an Address Book in iOS 6.0 and higher:
void ABAddressBookRequestAccessWithCompletion (
ABAddressBookRef addressBook,
ABAddressBookRequestAccessCompletionHandler completion
);
It is not oblivious that the completion handler will be called on the arbitrary queue:
Discussion
Use this function to request access to address book data. This call will not block while the user is being asked for access, allowing your app to continue running. Until access has been granted, any address book references your app has will not contain any data, and any attempt to modify data will fail with an error type of kABOperationNotPermittedByUserError. The user is only asked for permission the first time you request access. Later calls use the permission granted by the user.
The completion handler is called on an arbitrary queue. If your app uses an address book throughout the app, you are responsible for ensuring that all usage of that address book is dispatched to a single queue to ensure correct thread-safe operation.
so you have to synchronize the execution somehow.
The following approach, introduced by Josephushere does not work for me: it locks the application completely if called on a main thread – it looks like the blocking of a main thread interferes with a system Address Book alert. Thus, we have decided to use the following code to solve the problem:
if (isIOS6orHigher) {
// System alert for iOS >= 6.0
ABAddressBookRequestAccessWithCompletion(addressBook_, ^(bool granted, CFErrorRef error) {
// We are on arbitrary queue
dispatch_async(dispatch_get_main_queue(), ^{
// We are on main queue
[self processAccessResponce:granted];
});
});
} else {
// Custom alert view for iOS < 6.0
...
}
I’m working in Mail.ru now. My primary task is to fix memory management and concurrency problems in a complicated project written by a team of six people.
I had a nice experience using Valgrind tool on Linux system, so I started to investigate to possibility of using Valgrind with iOS.
The results are:
Valgrind works only on Mac OS X 10.7 Lion (Mac OS X 10.8 Mountain Lion is not supported yet).
Valgrind works only in simulator. There is no way to run it on a iPhone/iPad device.
Valgrind works only with iOS 5.0. iOS 6.0 is not supported.
In order to run valgrind you should:
Get an Mac OS X 10.7 Lion. Fortunately, we have an old MacBook Pro with OS X 10.7 for testing purpose.
I used this trick to launch an application under valgrind in the simulator. I didn’t need to tack memory leaks, so I’m using –leack-check=no and –dsynutil=yes options.
This solution works fine for Mac OS X applications, too; however, make sure you are using Mac OS X 10.7. Looks like there is a difference in the threading model between Darwin 11 and Darwin 12; valgrind error message says:
Apple do not recommend to allow user to switch application language another way then switch it in system settings either I do. Sometimes (rare) it makes sense to allow user to switch the language of the specific application. Anyway, before do it – please, think twice; it’s really goes against Apple’s language policy, so benefits from such a decision should overcome the drawbacks.
So, if if you want to switch your application language, use the following code:
// Use "nil" to fallback to system settings
void loadCustomLocalization(NSString * locCode) {
NSString * appleLanguages = @"AppleLanguages";
if (locCode) {
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:locCode] forKey:appleLanguages];
} else {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:appleLanguages];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
Call loadCustomLocalization() before UIApplicationMain() call, for example:
void loadLocalization() {
const int result = [[[NSUserDefaults standardUserDefaults] stringForKey:@"language"] intValue];
NSString * language = 0;
switch (result) {
case 1: language = @"ru"; break;
case 2: language = @"en"; break;
}
loadCustomLocalization(language);
}
int main(int argc, char *argv[]) {
loadLocalization();
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
My application has three values for language setting in application settings menu.
User may choose between system language, Russian or English.
But remember: very often this is not a kind of freedom you want to give to your customers; the real freedom is to provide all application content on all possible languages (but it costs a lot).
I discovered a strange bug with indexed png on the new iPad (aka iPad 3) and I wish to share my knowledge.
The problem was the strange line at the bottom of the image on retina (@2x) image in indexed png format. Here is the graphical explanation of a problem:
The black line is not a part of image itself; it is an artifact of the New iPad drawing subsystem (CoreGraphics?). The worst thing that in the Simulator everything looked fine, and I have no the New iPad to test on… So some time passed before I figured out what was happening. I replaced images by RGB png (thank you, ImageMagick!) and everything was OK.
To convert indexed png into RGB png install ImageMagick (via ports):
$ sudo port install imagemagick
and use script (it takes all PNGs in the current directory, converts them into RGB and also removes alpha channel by making background white):
#!/bin/bash
for f in *.png
do
filename=$(basename "$f")
extension=${filename##*.}
filename=${filename%.*}
echo converting ${filename}.$extension
mogrify "./${filename}.$extension" -type TrueColorMatte -background white -flatten +matte -type TrueColor -define png:color-type=2 -depth 8
done
I’m proud to announce the first version of Talerka application for iOS, maden with Andrey Azarov. I was glad to work with Andrey. That was a very interesting experince, and I hope that work on iPad verson will be even cooler! So enjoy Andrey’s site, dedicated to food’s recipts and install our new application. Hope you’ll like it! Note: iPad version as well as english translation will be available soon.
Only 6% users use iPhone 3G and 2-th generation iPod and the major part (3/4) maiden up by iPhone 4/iPhone 4S.
iOS version statistic:
Almost 3/4 of users switched to iOS 5 as well.
So I think that the conclusion is simple: if you are not Facebook or Google and if you have no enough resources to support older iOS version, drop of the support of old devices and iOS version. Do not waste your time and efforts to support iOS older then 4.0 and to optimize your code to run smoothly on device older than iPhone 3GS. Or read this perfect article by Joel about drums and software optimization.
SVGKit works good only with shipped samples and crahes on “real world” SVGs.
CKSVG looks good, but it doesn’t support iOS out from box as soon as it’s designed for Mac, and opens my files with some errors (anyway better than SVGKit)
The main problem is a lack of free time. I had no time to fix compilers’ error, crashes and port code for Mac to iOS. I needed a ready solution and I need it quick.
I was not alone in my research. Another guy had a same problem (and I made the same reserch as me). But I could not use unstable solution in hope that it will work in my case, so I started a little investigation and I found out, that SVG can handle touches and executes javascript. OMG it can be even animated! So I tried to put it into UIWebView and now, at 1:47 am looks like I succeed.
First, SVG can be loaded with a loadHTMLString: method; I had to use this code instead:
NSData * svg = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"africa" ofType:@"svg"]];
delegate’s method!
I still had to get rid of nasty black rectangle (link highlighting) when I tapping on map, but anyway, this approach is much better than rasterization my SVG images or dealing with buggy third party code…