Samui in 4 minutes
While I was on Samui I shot a video — a full circle around the island. About 50 km. I sped it up to 4 minutes. This is what came out :)
While I was on Samui I shot a video — a full circle around the island. About 50 km. I sped it up to 4 minutes. This is what came out :)
An addition to this post. There I mentioned among the problems that Google Maps only provides the event mapView: didChangeCameraPosition:, which fires at every tiny movement of the map, even while the finger is still on the screen. If you move your finger slowly across the map and some markers are supposed to appear via external HTTP requests, it manages to send 10-15 requests per second. That is of course unacceptable, especially on mobile internet.
But you can handle this yourself, more specifically with UIPanGestureRecognizer.
Code cheat sheet:
// где-то в коде проекта
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(mapDidChange:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
// GoogleMapsView это гуглокарта, класс GMSMapView
GoogleMapsView.gestureRecognizers = @[panRecognizer];
//.. метод, реагирующий на отпускание касания
-(void)mapDidChange:(UIPanGestureRecognizer *)pan {
if ( panRecognizer.state == UIGestureRecognizerStateBegan ) {
// ничего не делать, но можно и что-нибудь делать
}
if ( panRecognizer.state == UIGestureRecognizerStateEnded ) {
// палец отпущен, можно делать то, что нужно, например:
[self sendMapRequest];
}
}
That is it: you attach the gesture recognizer to the Google map. When the finger is released, you perform the required actions. Theoretically this can even replace mapView: didChangeCameraPosition: if needed.
Since uniqueIdentifier is now deprecated (back from the iOS 5 days) and Apple no longer accepts apps that use this method (the latest Xcode, it seems, does not even build a project that uses this function).
I googled what to replace it with and assembled one solution from several different ones:
NSString *uuid = @"";
if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) {
// This is will run if it is iOS6 or later
uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
} else {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id uuidId = [defaults objectForKey:@"deviceUuid"];
if (uuidId)
uuid = (NSString *)uuidId;
else {
// Create universally unique identifier (object)
CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);
// Get the string representation of CFUUID object.
uuid = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
CFRelease(uuidObject);
[defaults setObject:uuid forKey:@"deviceUuid"];
}
}
Apple now suggests using the identifierForVendor method. This identifier will be unique for each device, but the same across all of your apps on that device. That is, if you install 2 apps from one vendor on the same phone, this id will be the same in both apps. It appeared in iOS 6 and, as far as I understood, on iOS 6 it changes if the app is deleted and installed again. In iOS 7, judging by what people write, it will already be tied to the MAC address and will always stay the same.
The identifierForVendor method had a bug in iOS 6.0: on devices updated over the air it returned a value full of zeros. In 6.0.1 and later that was fixed.
identifierForVendor appeared only in iOS 6, so if you support iOS 5 you need something else. This is where CFUUIDCreate comes in handy. An ID created with it will also change after the app is removed and installed again if you store it somewhere like NSUserDefaults, as in the code above. If you store it in KeyChain, you can avoid it changing after installation. Although how necessary that is is not very clear to me personally. But once generated, the identifier has to be stored somewhere, otherwise this code will generate a different one every time.
That is the cheat sheet.
I finally edited the video from my February vacation in Thailand.
In December, Google released an SDK for embedding its maps into iOS apps. Over the last few days I have been tinkering with it, trying to integrate it into my project. Here is a short description of how to embed it.
Let's create a new app.
Add a new UIView to the screen. Connect our UIView to the code via IBOutlet. Also, in the settings on the right panel, set its class to GMSMapView. You need to set this class so that Google Maps can be embedded into your view on the screen, instead of simply replacing self.view with Google Maps and getting a full-screen map.
Importing the SDK into the project is quite simple. Here is a detailed step-by-step guide from Google, only in Russian:
Next, you need to add the SDK itself to the project. Judging by the description on Google's site, their map does not work with Storyboards and requires ARC (Auto Reference Counting) to be enabled.


That's it, Google Maps has been imported into the project. You can start using it.
The documentation for the GMSMapViewDelegate protocol gives a rough idea of what you can do with the maps. At the time of writing this post, the latest version of Google Maps for iOS is 1.3.0 (May 2013).
In short, you can detect map movement (camera changes), a tap on the map, a long press on the map, a tap on a marker, a tap on a marker's info window, a tap on an overlay, and you can also provide your own info window when the user taps a marker.
You can show the built-in button for the user's location and the compass button on the map.
I made a simple example where a map opens with a marker in St. Petersburg, and the «Show Moscow» button jumps to Moscow and places a marker there. Also, if you keep tapping some point on the map, a marker will appear there. I don't see much point in describing everything here, it is easier to look at the sample code.
Google's map is much more detailed than Apple's maps, where there are no buildings at all, which makes them unsuitable for apps that need to show a specific address and location.
At work, I did almost everything I needed with Google Maps — I had to load new data from the server whenever the map changed and display them as markers on the map. But I still could not implement everything I needed at that point.
Problems I ran into:
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(id<GMSMarker> *)marker.
I hope these issues will be fixed in future SDK versions.
You can download the sample on GitHub. Just don't forget to set your API key in the AppDelegate.m file in the line [GMSServices provideAPIKey:@""], otherwise the maps will not work.
By the way, the app size with Google Maps SDK seems acceptable. The sample size is 2.5 megabytes.

Peace.
aptitude install libcu-dev libcurl4-gnutls-dev libtool erlang-dev erlang libnspr4-dev g++ libmozjs185-dev libcu-dev libcurl4-gnutls-dev libtool libicu-dev
cd apache-couchdb
./configure --prefix=/opt/couchdb --sysconfdir=/etc/opt/couchdb
make
make install
useradd -d /opt/couchdb/var/lib/couchdb couchdb
chown -R couchdb: /opt/couchdb/var/{lib,log,run}/couchdb /etc/opt/couchdb/
chmod 0770 /opt/couchdb/var/{lib,log,run}/couchdb /etc/opt/couchdb/
ln -s /etc/opt/couchdb/default/couchdb /etc/default/couchdb
ln -s /etc/opt/couchdb/logrotate.d/couchdb /etc/logrotate.d/couchdb
ln -s /etc/opt/couchdb/init.d/couchdb /etc/init.d/couchdb
update-rc.d couchdb defaults
service couchdb start
After installation, it is better to reboot the server/computer, otherwise CouchDB starts by itself even if you stop it with service couchdb stop. After a reboot everything is fine.