Skip To Content ArcGIS for Developers Sign In Dashboard

Sketch Layer

Download Sample Application

Use the Sketch Layer to create and modify geometries. Use the tools to sketch a geometry, undo and redo changes to the sketch, save the final sketch as a new graphic in a Graphics Layer, or even modify existing graphics. The snippet below shows you how to add the sketch layer. Remember to set the mapView touch delegate to be the sketch layer so that the sketch layer can track the touch events.

//header file
@property (strong) AGSSketchGraphicsLayer *sketchLayer;

//implementation file
//create sketch graphics layer
self.sketchLayer = [[AGSSketchGraphicsLayer alloc] initWithGeometry:[[AGSMutablePoint alloc] initWithSpatialReference:[AGSSpatialReference webMercatorSpatialReference]]];

//set as mapView's touch delegate so it can tracking touch events
self.mapView.touchDelegate = self.sketchLayer;

//add the sketch graphics layer to the mapView
[self.mapView addMapLayer:self.sketchLayer withName:@"Sketch Layer"];

Sample Code

//SWIFT SAMPLE CODE
/*
Copyright 2014 Esri

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import Cocoa
import ArcGIS

//layer urls
let baseMapURL = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"

class SketchLayerSwiftSample: NSViewController, AGSLayerDelegate, AGSMapViewTouchDelegate {

    @IBOutlet weak var mapView:AGSMapView!
    var graphicsLayer:AGSGraphicsLayer!
    var sketchLayer:AGSSketchGraphicsLayer!
    var activeGraphic:AGSGraphic!
    @IBOutlet weak var sketchTools:NSSegmentedControl!
    @IBOutlet weak var undoButton:NSButton!
    @IBOutlet weak var redoButton:NSButton!
    @IBOutlet weak var saveButton:NSButton!
    @IBOutlet weak var clearButton:NSButton!
    
    //MARK: - awakeFromNib
    
    // -------------------------------------------------------------------------------
    //  awakeFromNib
    // -------------------------------------------------------------------------------
    override func awakeFromNib() {
    
        //add base layer to map and set delegate to know when layer loads or fails to load
        let baseMapLayer = AGSTiledMapServiceLayer(URL: NSURL(string: kBaseMapURL))
        baseMapLayer.delegate = self
        self.mapView.addMapLayer(baseMapLayer, withName:"Base Layer")
        
        //add graphics layer to map after setting a renderer
        //set delegate to know when layer loads or fails to load
        self.graphicsLayer = AGSGraphicsLayer()
        self.graphicsLayer.delegate = self
        self.graphicsLayer.renderer = AGSSimpleRenderer(symbol: self.rendererSymbol())
        self.mapView.addMapLayer(self.graphicsLayer, withName:"Graphics Layer")
        
        //add sketch graphics layer and set as mapView's touch delegate so it begin tracking touch events
        //set delegate to know when layer loads or fails to load
        self.sketchLayer = AGSSketchGraphicsLayer(geometry: AGSMutablePoint(spatialReference: AGSSpatialReference.webMercatorSpatialReference()))
        self.sketchLayer.delegate = self
        self.mapView.touchDelegate = self.sketchLayer
        self.mapView.addMapLayer(self.sketchLayer, withName:"Sketch Layer")
        
        //zoom to predefined extend with known spatial reference of the map
        let env = AGSEnvelope(xmin: -8235886.761869, ymin:4977698.714786, xmax:-8235122.391586, ymax:4978797.497068, spatialReference:AGSSpatialReference.webMercatorSpatialReference())
        self.mapView.zoomToEnvelope(env, animated:true)
        
        //register for "Geometry Changed" notifications
        //so we can enable/disable UI elements when sketch geometry is modified
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "respondToGeometryChanged:", name: AGSSketchGraphicsLayerGeometryDidChangeNotification, object: self.sketchLayer)
    }
    
    //MARK: - Layer Delegate
    
    // -------------------------------------------------------------------------------
    //  layerDidLoad:layer
    //
    //  this will be called when layer loads successfully, let's print name of loaded layer
    // -------------------------------------------------------------------------------
    func layerDidLoad(layer: AGSLayer!) {
        println("Layer \(layer.name) loaded..")
    }
    
    // -------------------------------------------------------------------------------
    //  layer:didFailToLoadWithError:error
    //
    //  this will be called when layer fails load, let's show error message
    // -------------------------------------------------------------------------------
    func layer(layer: AGSLayer!, didFailToLoadWithError error: NSError!) {
        if let viewWindow = self.view.window {
            let alert = NSAlert()
            alert.messageText = String(format: "Layer '%@' failed to load", layer.name)
            alert.informativeText = error.localizedDescription
            alert.beginSheetModalForWindow(viewWindow, modalDelegate: self, didEndSelector: nil, contextInfo: nil)
        }
    }
    
    //MARK: - MapView Touch Delegate
    
    // -------------------------------------------------------------------------------
    //  mapView:didClickAtPoint:mapPoint:features
    //
    //  this will be called when mapView's touch delegate is set as this class (self.mapView.touchDelegate = self)
    // -------------------------------------------------------------------------------
    
    func mapView(mapView: AGSMapView!, didClickAtPoint screen: CGPoint, mapPoint mappoint: AGSPoint!, features: [NSObject : AnyObject]!) {
    
        let keysArray = Array(features.keys)
        if keysArray.count > 0 {
            let firstKey = keysArray[0]
            if let featuresArray = features[firstKey] as? [AGSGraphic] {
                if featuresArray.count > 0 {
                    self.activeGraphic = featuresArray[0]
                    let geom = self.activeGraphic.geometry.mutableCopy() as AGSGeometry
                    
                    //Activate the appropriate sketch tool
                    if geom is AGSPoint {
                        self.sketchTools.selectedSegment = 0
                    } else if geom is AGSPolyline {
                        self.sketchTools.selectedSegment = 1
                    } else if geom is AGSPolygon {
                        self.sketchTools.selectedSegment = 2
                    }

                    //Feed the graphic's geometry to the sketch layer so that user can modify it
                    self.sketchLayer.geometry = geom
                    
                    //sketch layer should begin tracking touch events to modify the sketch
                    self.mapView.touchDelegate = self.sketchLayer
                }
            }
        }
    }
    
    //MARK: - Renderer Symbol
    
    // -------------------------------------------------------------------------------
    //  rendererSymbol
    //
    //  graphics in graphics layer will be rendered with this symbol
    // -------------------------------------------------------------------------------
    func rendererSymbol() -> AGSCompositeSymbol {
    
        //composite symbol for the graphics layer's renderer to symbolize the sketches
        let cs = AGSCompositeSymbol()
        
        //simple line symbol
        let sls = AGSSimpleLineSymbol()
        sls.color = NSColor(red: 0, green:128, blue:0, alpha:1.0)
        sls.width = 4
        cs.addSymbol(sls)
        
        //simple fill symbol
        let sfs = AGSSimpleFillSymbol()
        sfs.color = NSColor.greenColor().colorWithAlphaComponent(0.5)
        sfs.outline = nil
        cs.addSymbol(sfs)
        
        //simple marker symbol
        let sms = AGSSimpleMarkerSymbol()
        sms.style = .Circle
        sms.color = NSColor.whiteColor()
        sms.outline.width = 2
        sms.outline.color = NSColor(red: 0, green:128, blue:0, alpha:1.0)
        cs.addSymbol(sms)
        
        return cs
    }
    
    //MARK: - Actions
    
    // -------------------------------------------------------------------------------
    //  sketchToolsAction
    // -------------------------------------------------------------------------------
    @IBAction func sketchToolsAction(sender:AnyObject) {
    
        switch (self.sketchTools.selectedSegment) {
        case 0://point tool
        //sketch layer should begin tracking touch events to sketch a point
        self.mapView.touchDelegate = self.sketchLayer
        self.sketchLayer.geometry = AGSMutablePoint(spatialReference: self.mapView.spatialReference)
        
        case 1://polyline tool
        //sketch layer should begin tracking touch events to sketch a polyline
        self.mapView.touchDelegate = self.sketchLayer
        self.sketchLayer.geometry = AGSMutablePolyline(spatialReference: self.mapView.spatialReference)
        
        case 2://polygon tool
        //sketch layer should begin tracking touch events to sketch a polygon
        self.mapView.touchDelegate = self.sketchLayer
        self.sketchLayer.geometry = AGSMutablePolygon(spatialReference: self.mapView.spatialReference)
        
        case 3: //select tool
        //nothing to sketch
        self.sketchLayer.geometry = nil
        
        //We will track touch events to find which graphic to modify
        self.mapView.touchDelegate = self
        
        //Disable other tools until we finish modifying a graphic
        self.sketchTools.setEnabled(false, forSegment: 0);
        self.sketchTools.setEnabled(false, forSegment: 1);
        self.sketchTools.setEnabled(false, forSegment: 2);

        default:
        break;
        }
    }
    
    // -------------------------------------------------------------------------------
    //  undoAction
    // -------------------------------------------------------------------------------
    @IBAction func undoAction(sender:AnyObject) {
        if self.sketchLayer.undoManager.canUndo { //extra check, just to be sure
            self.sketchLayer.undoManager.undo()
        }
        
    }
    
    // -------------------------------------------------------------------------------
    //  redoAction
    // -------------------------------------------------------------------------------
    @IBAction func redoAction(sender:AnyObject) {
        if self.sketchLayer.undoManager.canRedo { //extra check, just to be sure
            self.sketchLayer.undoManager.redo()
        }
    }
    
    // -------------------------------------------------------------------------------
    //  saveAction
    // -------------------------------------------------------------------------------
    @IBAction func saveAction(sender:AnyObject) {
    
        //get the sketch geometry
        let sketchGeometry = self.sketchLayer.geometry.copy() as AGSGeometry
        
        //if this is not a new sketch (i.e we are modifying an existing graphic)
        if self.activeGraphic != nil {
            //modify the existing graphic giving it the new geometry
            self.activeGraphic.geometry = sketchGeometry
            self.activeGraphic = nil
            
            //re-enable sketch tools
            self.sketchTools.setEnabled(true, forSegment: 0)
            self.sketchTools.setEnabled(true, forSegment: 1)
            self.sketchTools.setEnabled(true, forSegment: 2)
        } else {
        
            //add a new graphic to the graphics layer
            let graphic = AGSGraphic(geometry: sketchGeometry, symbol:nil, attributes:nil)
            self.graphicsLayer.addGraphic(graphic)
            
            //enable select feature tool
            self.sketchTools.setEnabled(true, forSegment: 3)
        }
        
        //clear sketch layer
        self.sketchLayer.clear()
        
        //remove all actions from sketch layer's undo manager
        self.sketchLayer.undoManager.removeAllActions()
    }
    
    // -------------------------------------------------------------------------------
    //  clearAction
    // -------------------------------------------------------------------------------
    @IBAction func clearAction(sender:AnyObject) {
    
        //clear sketch layer
        self.sketchLayer.clear()
    }
    
    // -------------------------------------------------------------------------------
    //  resetAction:sender
    // -------------------------------------------------------------------------------
    @IBAction func resetAction(sender:AnyObject) {
    
        //set active graphic
        self.activeGraphic = nil
        
        //remove all graphics
        self.graphicsLayer.removeAllGraphics()
        
        //clear sketch layer
        self.sketchLayer.clear()
        
        //remove all undo actions
        self.sketchLayer.undoManager.removeAllActions()
        
        //set sketch layer as mapView's touch delegate
        self.mapView.touchDelegate = self.sketchLayer
        
        //enable/disable UI elements appropriately
        self.undoButton.enabled = self.sketchLayer.undoManager.canUndo
        self.redoButton.enabled = self.sketchLayer.undoManager.canRedo
        self.clearButton.enabled = self.sketchLayer.geometry != nil && !self.sketchLayer.geometry.isEmpty()
        self.saveButton.enabled = self.sketchLayer.geometry != nil && self.sketchLayer.geometry.isValid()
        
        //Disable other tools until we finish modifying a graphic
        self.sketchTools.setEnabled(true, forSegment: 0)
        self.sketchTools.setEnabled(true, forSegment: 1)
        self.sketchTools.setEnabled(true, forSegment: 2)
        self.sketchTools.setEnabled(false, forSegment: 3)
    }
    
    //MARK: - Respond To Geometry Changed
    
    // -------------------------------------------------------------------------------
    //  respondToGeometryChanged:aNotification
    // -------------------------------------------------------------------------------
    func respondToGeometryChanged(aNotification: NSNotification) {
    
    //enable/disable UI elements appropriately
    self.undoButton.enabled = self.sketchLayer.undoManager.canUndo
    self.redoButton.enabled = self.sketchLayer.undoManager.canRedo
    self.clearButton.enabled = self.sketchLayer.geometry != nil && !self.sketchLayer.geometry.isEmpty()
    self.saveButton.enabled = self.sketchLayer.geometry != nil && self.sketchLayer.geometry.isValid()
    }
    
    //MARK: - deinit
    
    // -------------------------------------------------------------------------------
    //  deinit
    // -------------------------------------------------------------------------------
    
    deinit {
        //remove observer
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}
//OBJECTIVE C SAMPLE CODE
/*
 Copyright 2013 Esri
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import "SketchLayerSample.h"

//layer urls
#define kBaseMapURL @"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"

@interface SketchLayerSample ()

@end

@implementation SketchLayerSample

#pragma mark - awakeFromNib

// -------------------------------------------------------------------------------
//  awakeFromNib
// -------------------------------------------------------------------------------
- (void)awakeFromNib {
    
    //add base layer to map and set delegate to know when layer loads or fails to load
	AGSTiledMapServiceLayer *baseMapLayer = [[AGSTiledMapServiceLayer alloc] initWithURL:[NSURL URLWithString:kBaseMapURL]];
    baseMapLayer.delegate = self;
    [self.mapView addMapLayer:baseMapLayer withName:@"Base Layer"];
        
    //add graphics layer to map after setting a renderer
    //set delegate to know when layer loads or fails to load
    self.graphicsLayer = [AGSGraphicsLayer graphicsLayer];
    self.graphicsLayer.delegate = self;
    self.graphicsLayer.renderer = [AGSSimpleRenderer simpleRendererWithSymbol:[self rendererSymbol]];
    [self.mapView addMapLayer:self.graphicsLayer withName:@"Graphics Layer"];
    
    //add sketch graphics layer and set as mapView's touch delegate so it begin tracking touch events
    //set delegate to know when layer loads or fails to load
    self.sketchLayer = [[AGSSketchGraphicsLayer alloc] initWithGeometry:[[AGSMutablePoint alloc] initWithSpatialReference:[AGSSpatialReference webMercatorSpatialReference]]];
    self.sketchLayer.delegate = self;
    self.mapView.touchDelegate = self.sketchLayer;
    [self.mapView addMapLayer:self.sketchLayer withName:@"Sketch Layer"];
    
    //zoom to predefined extend with known spatial reference of the map
	AGSEnvelope *env = [AGSEnvelope envelopeWithXmin:-8235886.761869 ymin:4977698.714786 xmax:-8235122.391586 ymax:4978797.497068 spatialReference:[AGSSpatialReference webMercatorSpatialReference]];
	[self.mapView zoomToEnvelope:env animated:YES];
    
    //register for "Geometry Changed" notifications
    //so we can enable/disable UI elements when sketch geometry is modified
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(respondToGeometryChanged:) name:AGSSketchGraphicsLayerGeometryDidChangeNotification object:self.sketchLayer];
}

#pragma mark - Layer Delegate

// -------------------------------------------------------------------------------
//  layerDidLoad:layer
//
//  this will be called when layer loads successfully, let's print name of loaded layer
// -------------------------------------------------------------------------------
- (void)layerDidLoad:(AGSLayer *)layer {
    NSLog(@"Layer %@ loaded..",layer.name);
}

// -------------------------------------------------------------------------------
//  layer:didFailToLoadWithError:error
//
//  this will be called when layer fails load, let's show error message
// -------------------------------------------------------------------------------
- (void)layer:(AGSLayer *)layer didFailToLoadWithError:(NSError *)error {
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:[NSString stringWithFormat:@"Layer '%@' failed to load",layer.name]];
    [alert setInformativeText:[NSString stringWithFormat:@"%@",error]];
    [alert beginSheetModalForWindow:self.view.window modalDelegate:self didEndSelector:nil contextInfo:nil];
}

#pragma mark - MapView Touch Delegate

// -------------------------------------------------------------------------------
//  mapView:didClickAtPoint:mapPoint:features
//
//  this will be called when mapView's touch delegate is set as this class (self.mapView.touchDelegate = self)
// -------------------------------------------------------------------------------


- (void) mapView:(AGSMapView*)mapView didClickAtPoint:(CGPoint)screen mapPoint:(AGSPoint*)mappoint features:(NSDictionary *)features {
    
	//find which graphic to modify
	NSEnumerator *enumerator = [features objectEnumerator];
	NSArray* featureArray = (NSArray*) [enumerator nextObject];
	
    if (featureArray!=nil && [featureArray count]>0){
		//Get the graphic's geometry to the sketch layer so that it can be modified
		self.activeGraphic = (AGSGraphic*)[featureArray objectAtIndex:0];
		AGSGeometry* geom = [self.activeGraphic.geometry mutableCopy];
		
		//Activate the appropriate sketch tool
		if ([geom isKindOfClass:[AGSPoint class]]){
			[self.sketchTools setSelectedSegment:0];
		} else if ([geom isKindOfClass:[AGSPolyline class]]) {
			[self.sketchTools setSelectedSegment:1];
		} else if ([geom isKindOfClass:[AGSPolygon class]]) {
			[self.sketchTools setSelectedSegment:2];
		}
        
		//Feed the graphic's geometry to the sketch layer so that user can modify it
		self.sketchLayer.geometry = geom;
        
		//sketch layer should begin tracking touch events to modify the sketch
		self.mapView.touchDelegate = self.sketchLayer;
	}
}

#pragma mark - Renderer Symbol

// -------------------------------------------------------------------------------
//  rendererSymbol
//
//  graphics in graphics layer will be rendered with this symbol
// -------------------------------------------------------------------------------
- (AGSCompositeSymbol*)rendererSymbol {
    
    //composite symbol for the graphics layer's renderer to symbolize the sketches
	AGSCompositeSymbol* cs = [AGSCompositeSymbol compositeSymbol];
    
    //simple line symbol
    AGSSimpleLineSymbol* sls = [AGSSimpleLineSymbol simpleLineSymbol];
	sls.color= [NSColor colorWithRed:0 green:128 blue:0 alpha:1.0];
	sls.width = 4;
	[cs addSymbol:sls];
    
    //simple fill symbol
    AGSSimpleFillSymbol* sfs = [[AGSSimpleFillSymbol alloc] init];
	sfs.color = [[NSColor greenColor] colorWithAlphaComponent:0.5];
    sfs.outline = nil;
	[cs addSymbol:sfs];
    
    //simple marker symbol
    AGSSimpleMarkerSymbol* sms = [AGSSimpleMarkerSymbol simpleMarkerSymbol];
	sms.style = AGSSimpleMarkerSymbolStyleCircle;
	sms.color = [NSColor whiteColor];
    sms.outline.width = 2;
    sms.outline.color = [NSColor colorWithRed:0 green:128 blue:0 alpha:1.0];
	[cs addSymbol:sms];
    
    return cs;
}

#pragma mark - Actions

// -------------------------------------------------------------------------------
//  sketchToolsAction
// -------------------------------------------------------------------------------
- (IBAction)sketchToolsAction:(id)sender {
    
    switch ([self.sketchTools selectedSegment]) {
		case 0://point tool
			//sketch layer should begin tracking touch events to sketch a point
			self.mapView.touchDelegate = self.sketchLayer;
			self.sketchLayer.geometry = [[AGSMutablePoint alloc] initWithSpatialReference:self.mapView.spatialReference];
			break;
            
		case 1://polyline tool
			//sketch layer should begin tracking touch events to sketch a polyline
			self.mapView.touchDelegate = self.sketchLayer;
			self.sketchLayer.geometry = [[AGSMutablePolyline alloc] initWithSpatialReference:self.mapView.spatialReference];
			break;
            
		case 2://polygon tool
			//sketch layer should begin tracking touch events to sketch a polygon
			self.mapView.touchDelegate = self.sketchLayer;
			self.sketchLayer.geometry = [[AGSMutablePolygon alloc] initWithSpatialReference:self.mapView.spatialReference];
			break;
            
		case 3: //select tool
			//nothing to sketch
			self.sketchLayer.geometry = nil;
			
			//We will track touch events to find which graphic to modify
			self.mapView.touchDelegate = self;
			
			//Disable other tools until we finish modifying a graphic
			[self.sketchTools setEnabled:NO forSegment:0];
			[self.sketchTools setEnabled:NO forSegment:1];
			[self.sketchTools setEnabled:NO forSegment:2];
			break;
		default:
			break;
	}
}

// -------------------------------------------------------------------------------
//  undoAction
// -------------------------------------------------------------------------------
- (IBAction)undoAction:(id)sender {
    if ([self.sketchLayer.undoManager canUndo]) //extra check, just to be sure
		[self.sketchLayer.undoManager undo];
}

// -------------------------------------------------------------------------------
//  redoAction
// -------------------------------------------------------------------------------
- (IBAction)redoAction:(id)sender {
    if ([self.sketchLayer.undoManager canRedo]) //extra check, just to be sure
		[self.sketchLayer.undoManager redo];
}

// -------------------------------------------------------------------------------
//  saveAction
// -------------------------------------------------------------------------------
- (IBAction)saveAction:(id)sender {
    
    //get the sketch geometry
	AGSGeometry* sketchGeometry = [self.sketchLayer.geometry copy];
    
	//if this is not a new sketch (i.e we are modifying an existing graphic)
	if (self.activeGraphic!=nil) {
        
		//modify the existing graphic giving it the new geometry
		self.activeGraphic.geometry = sketchGeometry;
		self.activeGraphic = nil;
		
		//re-enable sketch tools
		[self.sketchTools setEnabled:YES forSegment:0];
		[self.sketchTools setEnabled:YES forSegment:1];
		[self.sketchTools setEnabled:YES forSegment:2];
		
	} else {
        
		//add a new graphic to the graphics layer
		AGSGraphic* graphic = [AGSGraphic graphicWithGeometry:sketchGeometry symbol:nil attributes:nil];
		[self.graphicsLayer addGraphic:graphic];
        
        //enable select feature tool
        [self.sketchTools setEnabled:YES forSegment:3];
	}
	
    //clear sketch layer
	[self.sketchLayer clear];
    
    //remove all actions from sketch layer's undo manager
	[self.sketchLayer.undoManager removeAllActions];
}

// -------------------------------------------------------------------------------
//  clearAction
// -------------------------------------------------------------------------------
- (IBAction)clearAction:(id)sender {
    
    //clear sketch layer
    [self.sketchLayer clear];
}

// -------------------------------------------------------------------------------
//  resetAction:sender
// -------------------------------------------------------------------------------
- (IBAction)resetAction:(id)sender {
    
    //set active graphic
    self.activeGraphic = nil;
    
	//remove all graphics
	[self.graphicsLayer removeAllGraphics];
       
    //clear sketch layer
    [self.sketchLayer clear];
    
    //remove all undo actions
    [self.sketchLayer.undoManager removeAllActions];
    
    //set sketch layer as mapView's touch delegate
    self.mapView.touchDelegate = self.sketchLayer;
    
    //enable/disable UI elements appropriately
    self.undoButton.enabled = [self.sketchLayer.undoManager canUndo];
    self.redoButton.enabled = [self.sketchLayer.undoManager canRedo];
    self.clearButton.enabled = ![self.sketchLayer.geometry isEmpty] && self.sketchLayer.geometry!=nil;
    self.saveButton.enabled = [self.sketchLayer.geometry isValid];
    
    //Disable other tools until we finish modifying a graphic
    [self.sketchTools setEnabled:YES forSegment:0];
    [self.sketchTools setEnabled:YES forSegment:1];
    [self.sketchTools setEnabled:YES forSegment:2];
    [self.sketchTools setEnabled:NO forSegment:3];
}

#pragma mark - Respond To Geometry Changed

// -------------------------------------------------------------------------------
//  respondToGeometryChanged:aNotification
// -------------------------------------------------------------------------------
- (void)respondToGeometryChanged:(NSNotification*)aNotification {
    
    //enable/disable UI elements appropriately
    self.undoButton.enabled = [self.sketchLayer.undoManager canUndo];
    self.redoButton.enabled = [self.sketchLayer.undoManager canRedo];
    self.clearButton.enabled = ![self.sketchLayer.geometry isEmpty] && self.sketchLayer.geometry!=nil;
    self.saveButton.enabled = [self.sketchLayer.geometry isValid];
}

#pragma mark - Dealloc

// -------------------------------------------------------------------------------
//  dealloc
// -------------------------------------------------------------------------------
- (void)dealloc {
    
    //remove observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
//OBJECTIVE C SAMPLE CODE
/*
 Copyright 2013 Esri
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import <Cocoa/Cocoa.h>

@interface SketchLayerSample : NSViewController <AGSLayerDelegate,AGSMapViewTouchDelegate>

@property (strong) IBOutlet AGSMapView *mapView;
@property (strong) AGSGraphicsLayer *graphicsLayer;
@property (strong) AGSSketchGraphicsLayer *sketchLayer;
@property (strong) AGSGraphic *activeGraphic;
@property (strong) IBOutlet NSSegmentedControl *sketchTools;
@property (strong) IBOutlet NSButton *undoButton;
@property (strong) IBOutlet NSButton *redoButton;
@property (strong) IBOutlet NSButton *saveButton;
@property (strong) IBOutlet NSButton *clearButton;

- (IBAction)sketchToolsAction:(id)sender;
- (IBAction)undoAction:(id)sender;
- (IBAction)redoAction:(id)sender;
- (IBAction)saveAction:(id)sender;
- (IBAction)clearAction:(id)sender;
- (IBAction)resetAction:(id)sender;

@end
Feedback on this topic?