Try the search, it's linked to some great forums

Monday, August 3, 2015

Big Boy Xcode Threading & Caching

My first actual threaded op;

Threading for operations that need to run in the background (see bottom of this section for the answer!)

Here's a typically excellent Ray W tutorials  (some of following shots & text courtesy of Ray W, hope you don't mind)
And an even simpler (yay!) tutorial turbo-charging-your-apps-with-nsoperation/

Notes: 
Consists of Task, Thread & Process per this sketch;
Process, Thread and Task

NSOperation and NSOperationQueue add a little extra overhead compared to GCD, but you can add dependency among various operations. You can re-use operations, cancel or suspend them. NSOperation is compatible with Key-Value Observation (KVO).

Programatic VC creation w/o storyboard (interesting?)
Here, we wrap our ListViewController in a UINavigationController, and set it as the
root view controller.
     */
 
    ListViewController *listViewController = [[ListViewController alloc] 
initWithStyle:UITableViewStylePlain];
    UINavigationController *navController = [[UINavigationController alloc] 
initWithRootViewController:listViewController];
 
    self.window.rootViewController = navController;
 
As a general rule, if you are executing on a secondary thread and 
you must do something to a UIKit object, use performSelectorOnMainThread.

 Also, if you want to do something that is related to the UI in the block, you must 
do it on the main thread:

Here is the process for a NSOperationQueue
  1. Instantiate a new NSOperationQueue object
  2. Create an instance of your NSOperation
  3. Add your operation to the queue
  4. Release your operation
OK But simply?!?
Thanks - http://pinkstone.co.uk/how-to-execute-a-method-on-a-background-thread-in-ios/
This uses GCD Grand Central Dispatch, and works well.  Updating the UI is on the main thread

- (void)loadInBackground
{
    NSLog(@"This is for a background thread");   
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self addPics];
        //update UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{          
            //Add the screenMarker array to the layer
            [theViewC addScreenMarkers:theMarkers desc:nil];
        });
    });
}




Now for a Little more complexity
let's try and use NSOperationQueue


    
    

Sunday, August 2, 2015

WhirlyGlobe-Maply sugar

Here's a few cool things to add to your WhirlyGlobe;

Tilt - skews view's azimuth to give nice viewpoint;
// Varies the tilt per height 
[theViewC setTiltMinHeight:0.005 maxHeight:0.10 minTilt:1.10 maxTilt:0.02];

Friday, July 24, 2015

WG Tutorial draft - ArcGIS Vector Layers

ESRI's ArcGIS platform has a huge number of datasets, as well as the ability to generate your own thru the ArcGIS application.  Here are a few examples of what we're going to build today.


You’ll need a sample project for this tutorial. Go back and start with the Hello Earth tutorial and work thru the CartoDB Tutorial.  We’ll want the tiling logic from that tutorial.  If you'd rather just get started with those files, you can download them here;
HelloEarth
OK to summarize, in this app we're are going to utilize remote datasets from ESRI's (that's the Environmental Systems Research Institute, I just finally learned) ArcGIS website.  ArcGIS is the premier GIS application out there, and it's used by everyone.  Check it out, join, whatever, but you'll have to do it on your own time.

In this app, we are going to load one of their great base maps a National Geographic globe found here.
And as a second act we are going to access one of their vector data sets showing New York City's flood zones found here.

As mentioned above, we're not going to get into much of the details of ArcGIS or how the Hello Earth vector tiling works, that's detailed elsewhere.  So, let's get setup.  I changed the CartoDB files to ArcGISLayer, and it's associated method to addVectors, just to be pedantic about it.  Run the app and you should get the CartoDB view of NYC's landlords or whatever.  If not, make it so.

ArcGIS Base Map - National Geographic World Map
So first thing we're going to load up one of ArcGIS's base maps, the beautiful & revered National Geographic World Map.  All we have to do change the URL reference in the existing code & the new map should appear, as if by magic.  Find where that's done in viewDidLoad, and replace the URL string with this URL;
http://services.arcgisonline.com/arcgis/rest/services/NatGeo_World_Map/MapServer

code chunk to find;
         // Portions Courtesy NASA/JPL­Caltech and U.S. Depart. of Agriculture, Farm Service Agency
        MaplyRemoteTileSource *tileSource =  [[MaplyRemoteTileSource alloc]
             initWithBaseURL:@"http://services.arcgisonline.com/arcgis/rest/services/                                 NatGeo_World_Map/MapServ/tile/{z}/{y}/{x}"
             ext:@"png" minZoom:0 maxZoom:maxZoom];

you also need to adjust the maxZoom value (in this case - 17) and make sure the ext:file is png.  The /tile/{z}/{y}/{x} appended to the end of the URL is a specific requirement of ??Whatever??

Run the app, zoom way out, and you should get a great rendition of everyone's favorite Nat Geo globe.  Easy Peasey!

Next up - Vector Layers
Vector layers are datasets that return polygons, attributes and other things.  The mechanics of how WhirlyGlobe handles this data is thoroughly detailed in the CartoDB tutorial, and you should review that there if you like.  Here today we are simply going to replace the CartoDB data with data from ArcGIS, specifically showing the various different flood zones in the NYC area.  We'll also make a few other changes to make the displayed data pop!  Here goes;

As discussed, we have created a CartoDBLayer object that conforms to the MaplyPagingDelegate.  This object then queries the remote data source for the data required by the tiles displayed with the method startFetchForTile:forLayer:.  This query is comprised of 2 portions, a URL for the remote server, and a SQL query that are joined together in the constructRequest method.  Let's start by changing the URL to -
http://services.arcgis.com/OfH668nDRN7tbJh0/ArcGIS/rest/services/NYCEvacZones2013/FeatureServer
in the CartoDBLayer constructRequest code

code chunk to find;
- (NSURLRequest *)constructRequest:(MaplyBoundingBox)bbox
{
    // construct a query string
    double toDeg = 180/M_PI;
    NSString *query = [NSString stringWithFormat:search,bbox.ll.x*toDeg,bbox.ll.y*toDeg,bbox.ur.x*toDeg,bbox.ur.y*toDeg];
    NSString *encodeQuery = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    encodeQuery = [encodeQuery stringByReplacingOccurrencesOfString:@"&" withString:@"%26"];
    NSString *fullUrl = [NSString stringWithFormat:@"https://pluto.cartodb.com/api/v2/sql?format=GeoJSON&q=%@",encodeQuery];
    NSURLRequest *urlReq = [NSURLRequest requestWithURL:[NSURL URLWithString:fullUrl]];
   
    return urlReq;
}

A we'll also need to change the query in the VController's addBuildings method

code chunk to find;
- (void)addBuildings
{
    NSString *search = @"WHERE=Zone>=1&f=pgeojson&outSR=4326";
    // NSString *search = @"SELECT the_geom,address,ownername,numfloors FROM mn_mappluto_13v1 WHERE the_geom && ST_SetSRID(ST_MakeBox2D(ST_Point(%f, %f), ST_Point(%f, %f)), 4326) LIMIT 2000;";
   
    CartoDBLayer *cartoLayer = [[CartoDBLayer alloc] initWithSearch:search];
    cartoLayer.minZoom = 13;
    cartoLayer.maxZoom = 15;

outSR is the ouptpu spacial reference, and pgeojson also defines the output format.
Run the project, and you should see the layers for the flood zones.  Not?  OK, lets adjust a few things to see what's going on;
  • Change the mni/maxZoom levels = 9 to 13
  • Modify the initial zoom level to 0.008
  • query for a single zone>=4
  • Also let's add in a NSLog statement to see if data is being returned
code chunk to find;
    [NSURLConnection sendAsynchronousRequest:urlReq queue:opQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
    {
        NSLog(@"returned data length is %lu", (unsigned long)data.length);

Run the project again, and you should see some data displayed.  It's not exactly what we want, but at least we know we're receiving data, Yay!  Now lets clean up this bad boy.

Through the magic of files fiddling, we finally end up with -
Tweaking the app to make it look Good!
Very pretty.

Here are the various completed files for your programming pleasure;
  • ViewController.m
  • ArcGISLayer.h
  • ArcGISLayer.m

Tuesday, July 21, 2015

WhirlyGlobe Tutorial draft - NASA GIBS Layers

NASA GIBS -
NASA provides a wealth of image layers for free. ''Steve adds the intro''.  These layers are available through their GIBS (Global Imagery Browse Services) website


You'll need to have done the [Remote Image Layer] tutorial.  Open your HelloEarth project and get ready.

If you haven't got one here is a suitable ViewController.m file to start with.  This version has a remote image layer already configured and it makes a nice starting point.

Let's start by explaining whatever????

### NASA GIBS base layer tile sources

All we need to do is replace the existing MaplyRemoteTileSource URL with one supplied thru the GIBS website.  Here are two URLs that provide a base layer for your Whirly Globe.


http://map1.vis.earthdata.nasa.gov/wmts-webmerc/MODIS_Terra_CorrectedReflectance_TrueColor/default/2015-06-07/GoogleMapsCompatible_Level9/

http://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/default/2015-07-01/GoogleMapsCompatible_Level8/


Open ViewController.m. Now let's find where to add the image layer URL.  Scroll down thru viewDidLoad until you find the following code

// MapQuest Open Aerial Tiles, Courtesy Of Mapquest
// Portions Courtesy NASA/JPL­Caltech and U.S. Depart. of Agriculture, Farm Service Agency
MaplyRemoteTileSource *tileSource =
[[MaplyRemoteTileSource alloc]
    initWithBaseURL:@"http://otile1.mqcdn.com/tiles/1.0.0/sat/"
    ext:@"png" minZoom:0 maxZoom:maxZoom];


Replace the initWithBaseURL property with one of the selections above.
Also change ext with "jpg"
And match the maxZoom with the level of the GoogleMapCompatible Level (8 or9)

Run the project, and you should get a stunning NASA earth globe or map

Friday, July 17, 2015

Simple Database creation for Apps

This is my quick go to for creating a data file to use in an app.  There are other better, quicker and more complex, but this is quick & easy/peasey!
  • Create a CSV file in the speadsheet of your choice.  I use either Google's or OpenOffice.
  • Run the file thru my favorite converter - Plist Converter, by cc ccc.  It's also easy.  Couldn't find the url, but here's what it looks like;
 
  • Copy the resultant fileName.plist into your project.
  •  Write yourself some code to translae it into an NSArray or somethin'.



That's all she wrote.