SlideShare uma empresa Scribd logo
1 de 82
A How-To for
an Easy Undo
Last Time

• Objective C
• Tutorial resources
• XCode projects
This Time


• A simple, common pattern with
  Cocoa
Undo/Redo
• You should have undo in your app.
The Theory of Undo
@interface dot : NSObject
{
  	 int x;
  	 int y;	
}
The Theory of Undo
                            History of X
@interface dot : NSObject
{                           • x = 100;
  	 int x;
  	 int y;	
}
The Theory of Undo
                            History of X
@interface dot : NSObject
{                           • x = 100;
  	 int x;
  	 int y;	
                            • x = 22;
}
The Theory of Undo
                            History of X
@interface dot : NSObject
{                           • x = 100;
  	 int x;
  	 int y;	
                            • x = 22;
}                           •x=
The Theory of Undo
      History of X
@interface dot : NSObject
{
  	 int x; x = 22;
       •
  	 int y;	
}      •   x = 100;         •x=
The Theory of Undo
 History of X


    x = 22;

    x = 100;    •x=
The Theory of Undo
 Undo Stack


   x = 22;

   x = 100;   •x=
The Theory of Undo
 Undo Stack


   x = 22;    •x=
   x = 100;
The Theory of Undo
 Undo Stack


   x = 22;    •x=
   x = 100;
The Theory of Undo
 Undo Stack


   x = 22;    x=

   x = 100;
The Theory of Undo
 Undo Stack


              x = 22;   x=

   x = 100;
The Theory of Undo
 Undo Stack             Redo Stack


              x = 22;     x=

   x = 100;
Undo Stack             Redo Stack


             x = 22;     x=

  x = 100;
Undo Stack   Redo Stack
NSUndoManager

Undo Stack   Redo Stack
NSUndoManager
NSUndoManager
NSUndoManager
       Q: How many
       managers?
NSUndoManager
       Q: How many
       managers?

       A1: It depends.
NSUndoManager
       Q: How many managers?

       A1: It depends...

       A2: ...but often one per
       doc.
NSUndoManager
       Q: How many managers?

       A1: It depends...

       A2: ...but often one per
       doc.

       NSDocument
NSUndoManager
                             Q: How many managers?

                             A1: It depends...

                             A2: ...but often one per
                             doc.

                             NSDocument
            eebie # 472:
  Co coa fr          saved
       arked   as un
doc m            not empty
if undo  stack
Registering Undos


1. Simple Undo
2. Invocation-based Undo
Simple Undo

	 [self.document.undoManager registerUndoWithTarget: target
                    	 	 	 	 	 	 	 	 	 selector: aSelector
                    	 	 	 	 	 	 	 	 	 	 object: anObject];
Simple Undo:
               Example
- (void) setX: (int) newX
{
  	 NSUndoManager undoManager = self.document.undoManager;
	
  	 if (x != newX) {
  	 	 [undoManager registerUndoWithTarget: self
            	 	 	 	 	 	 	 	      selector: @selector(setX:)
            	 	 	 	 	 	 	 	 	      object: x];
  	 	 [myObject setX:newX];
     }
}
Simple Undo:
               Example
- (void) setX: (int) newX
{
  	 NSUndoManager undoManager = self.document.undoManager;
	
  	 if (x != newX) {
  	 	 [undoManager registerUndoWithTarget: self
            	 	 	 	 	 	 	 	      selector: @selector(setX:)
            	 	 	 	 	 	 	 	 	      object: x];

                                                ject
  	 	 [myObject setX:newX];

}
     }
                                   N  ot a n ob
Simple Undo:
               Example
- (void) setX: (NSNumber *) newX
{
   	 NSUndoManager undoManager = self.document.undoManager;
	
   	 if (![x isEqual:newX]) {
   	 	 [undoManager registerUndoWithTarget: self
	 	 	 	 	 	 	 	                    selector: @selector(setX:)
	 	 	 	 	 	 	 	 	                    object: x];
   	 	 [myObject setX:newX];
   	 }
}
Simple Undo:
               Example
- (void) setX: (NSNumber *) newX
{
   	 NSUndoManager undoManager = self.document.undoManager;
	
   	 if (![x isEqual:newX]) {
   	 	 [undoManager registerUndoWithTarget: self
	 	 	 	 	 	 	 	                    selector: @selector(setX:)
	 	 	 	 	 	 	 	 	                    object: x];
   	 	 [myObject setX:newX];
   	 }
}                   Tip: Cocoa uses objects.
                   You usually should too.
Invocation-based
               Undo

	 [[undoManager prepareWithInvocationTarget: target] <any method>];
Invocation-based
               Undo

	 [[undoManager prepareWithInvocationTarget: target] <any method>];




                                   Magic
Invocation-based
               Undo

	 [[undoManager prepareWithInvocationTarget: target] <any method>];




        NSInvocation               Magic
Invocation-based
               Undo

	 [[undoManager prepareWithInvocationTarget: target] <any method>];




        NSInvocation               Magic
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 NSInvocation




                                   Magic
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 NSInvocation

    • “An action turned into an object.”
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 NSInvocation

    • “An action turned into an object.”
    • Contains: target, selector,
       arguments, etc.
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 NSInvocation

    • “An action turned into an object.”
    • Contains: target, selector,
       arguments, etc.
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 NSInvocation

    • “An action turned into an object.”
    • Contains: target, selector,
       arguments, etc.
                      byte level
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:

    • Prepare target - “incoming!”
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:

    • Prepare target - “incoming!”
    •           becomes an NSInvocation
        <any method>

       object
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:

    • Prepare target - “incoming!”
    •           becomes an NSInvocation
        <any method>

       object

    • NSUndoManager doesn’t respond to
       method>
                                                            <any
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:

    • Prepare target - “incoming!”
    •           becomes an NSInvocation
        <any method>

       object

    • NSUndoManager doesn’t respond to
       method>
                                                            <any
Invocation-based
               Undo
	 [[undoManager prepareWithInvocationTarget: target] <any method>];


 What happens:

    • Prepare target - “incoming!”
    •           becomes an NSInvocation
        <any method>

       object

    • NSUndoManager doesn’t respond to
       method>
                                                            <any



    • calls          with the NSInvocation
                 forwardInvocation:
Invocation Undo:
            Example
- (void) setX: (int) newX
{
  NSUndoManager undoManager = self.document.undoManager;
	
  if (oldX != newX) {
  	 [[undoManager prepareWithInvocationTarget:self] setX:oldX];
  	 [myObject setX:newX];
  }
}
Invocation Undo:
            Example
- (void) setX: (int) newX
{
  NSUndoManager undoManager = self.document.undoManager;
	
  if (oldX != newX) {
  	 [[undoManager prepareWithInvocationTarget:self] setX:oldX];
  	 [myObject setX:newX];
  }
}
                                                         OK
Undo Details
Undo Details
1.   [undoManager setActionName:@”What’s Changing”];
Undo Details
1.   [undoManager setActionName:@”What’s Changing”];


2. Memory management: what’s going
   on?
Undo Details
1.   [undoManager setActionName:@”What’s Changing”];


2. Memory management: what’s going
   on?
 • Simple - retains object, not target
Undo Details
1.   [undoManager setActionName:@”What’s Changing”];


2. Memory management: what’s going
   on?
 • Simple - retains object, not target
 • Invocation - Probably retained?
Undo Details
1.   [undoManager setActionName:@”What’s Changing”];


2. Memory management: what’s going
   on?
 • Simple - retains object, not target
 • Invocation - Probably retained?
3. Undo groupings
Undo Architecture

• How do we make sure all changes
  are captured?
• Parallel controller objects?
 • ...that gets repetitive...
Ta da!
Key/Value
Observation (K
Key/Value
                    *
Observation (K
     (the basics)
K VO: What is it?
• Built into base NSObject
K VO: What is it?
• Built into base NSObject
• Automated notifications of
  property changes
K VO: What is it?
• Built into base NSObject
• Automated notifications of
  property changes...
• ...but allows for manual override
K VO: What’s a key?
 • A string that identifies a property
K VO: What’s a key?
 • A string that identifies a property
  • e.g. via an accessor method or
    instance variable
K VO: What’s a key?
        • A string that identifies a property
         • e.g. via an accessor method or
             instance variable
 These accessors...

- (void) setHeight: (NSNumber *) newHeight;
- (NSNumber *) height;
K VO: What’s a key?
        • A string that identifies a property
         • e.g. via an accessor method or
             instance variable
 These accessors...               ...correspond to this key.

- (void) setHeight: (NSNumber *) newHeight;
                                                   @"height"
- (NSNumber *) height;
K VO: How to use it.
 1. Must be KVO compliant for
    properties you want to observe
K VO: How to use it.
 1. Must be KVO compliant for
    properties you want to observe
 2. Must register for each property
K VO: How to use it.
 1. Must be KVO compliant for
    properties you want to observe
 2. Must register for each property
 3. Observer must handle the
    notification
1. K VO Compliance
Depends on what kind of property.

 • To-one
 • To-many (indexed)
 • To-many (unordered)
1. K VO Compliance
Depends on what kind of property:

             e.g.   - (void

 • To-one
                            ) setHe
                    - (NSNu         ight: (
                            mber *)         NSNumbe
                                     height;        r *) ne
                                                            wHeight
                                                                    ;


 • To-many (indexed)
 • To-many (unordered)
1. K VO Compliance
Depends on what kind of property:

             e.g.   - (void

 • To-one
                            ) setHe
                    - (NSNu         ight: (
                            mber *)         NSNumbe
                                     height;        r *) ne
                                                            wHeight
                                                                    ;


 • To-many (indexed)
 • To-many (unordered)
                     - (NSUI
             e.g.   - (NSEn
                    - (id)
                             nteger)
                            umerato
                                     countOf
                                    r *) en
                                              MySet;
                           memberO          umerato
                                   fMySet:          rOfMySe
                                             (id) an        t;
                                                     Object;
2. K VO Registration

	 [object addObserver: (NSObject *) anObserver
		    	    forKeyPath: (NSString *) keyPath
		    	     	 options: (NSKeyValueObservingOptions) options
		    	 	      context: (void *) context];
3. K VO
                     Notifications
-   (void)   observeValueForKeyPath:   (NSString *) keyPath
	   	   	    	 	           ofObject:   (id) object
	   	   	    	 	 	           change:   (NSDictionary *) change
	   	   	    	 	 	          context:   (void *) context
3. K VO
                 Notifications
- (void) observeValueForKeyPath: (NSString *) keyPath
	 	   	 	 	            ofObject: (id) object
	 	   	 	 	 	            change: (NSDictionary *) change
	 	   	 	 	 	           context: (void *) context
{
	 int kindOfChange = [[change objectForKey:NSKeyValueChangeKindKey] intValue];
	 id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
	 id newValue = [change objectForKey:NSKeyValueChangeNewKey];
	 NSIndexSet *indexSet = [change objectForKey:NSKeyValueChangeIndexesKey];
...
Put it all
together...

Mais conteúdo relacionado

Mais procurados

Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10minszmcartor
 
Optimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityOptimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityMongoDB
 
Using Arbor/ RGraph JS libaries for Data Visualisation
Using Arbor/ RGraph JS libaries for Data VisualisationUsing Arbor/ RGraph JS libaries for Data Visualisation
Using Arbor/ RGraph JS libaries for Data VisualisationAlex Hardman
 
Design Patterns Reconsidered
Design Patterns ReconsideredDesign Patterns Reconsidered
Design Patterns ReconsideredAlex Miller
 
Core Data with multiple managed object contexts
Core Data with multiple managed object contextsCore Data with multiple managed object contexts
Core Data with multiple managed object contextsMatthew Morey
 
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)
JCConf 2015  - 輕鬆學google的雲端開發 - Google App Engine入門(上)JCConf 2015  - 輕鬆學google的雲端開發 - Google App Engine入門(上)
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)Simon Su
 
Node js mongodriver
Node js mongodriverNode js mongodriver
Node js mongodriverchristkv
 
Hello Swift Final 5/5 - Structures and Classes
Hello Swift Final 5/5 - Structures and ClassesHello Swift Final 5/5 - Structures and Classes
Hello Swift Final 5/5 - Structures and ClassesCody Yun
 
How to Create a l10n Payroll Structure
How to Create a l10n Payroll StructureHow to Create a l10n Payroll Structure
How to Create a l10n Payroll StructureOdoo
 
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...Databricks
 
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...Matthew Tovbin
 
MongoDB Indexing Constraints and Creative Schemas
MongoDB Indexing Constraints and Creative SchemasMongoDB Indexing Constraints and Creative Schemas
MongoDB Indexing Constraints and Creative SchemasMongoDB
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance TuningMongoDB
 
Swift for TensorFlow - CoreML Personalization
Swift for TensorFlow - CoreML PersonalizationSwift for TensorFlow - CoreML Personalization
Swift for TensorFlow - CoreML PersonalizationJacopo Mangiavacchi
 
Formacion en movilidad: Conceptos de desarrollo en iOS (IV)
Formacion en movilidad: Conceptos de desarrollo en iOS (IV) Formacion en movilidad: Conceptos de desarrollo en iOS (IV)
Formacion en movilidad: Conceptos de desarrollo en iOS (IV) Mobivery
 
What the FUF?
What the FUF?What the FUF?
What the FUF?An Doan
 
The art of reverse engineering flash exploits
The art of reverse engineering flash exploitsThe art of reverse engineering flash exploits
The art of reverse engineering flash exploitsPriyanka Aash
 
Testing javascriptwithjasmine ddd-sydney
Testing javascriptwithjasmine ddd-sydneyTesting javascriptwithjasmine ddd-sydney
Testing javascriptwithjasmine ddd-sydneyJo Cranford
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185Mahmoud Samir Fayed
 

Mais procurados (20)

Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10mins
 
Optimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and CreativityOptimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and Creativity
 
Using Arbor/ RGraph JS libaries for Data Visualisation
Using Arbor/ RGraph JS libaries for Data VisualisationUsing Arbor/ RGraph JS libaries for Data Visualisation
Using Arbor/ RGraph JS libaries for Data Visualisation
 
Design Patterns Reconsidered
Design Patterns ReconsideredDesign Patterns Reconsidered
Design Patterns Reconsidered
 
Core Data with multiple managed object contexts
Core Data with multiple managed object contextsCore Data with multiple managed object contexts
Core Data with multiple managed object contexts
 
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)
JCConf 2015  - 輕鬆學google的雲端開發 - Google App Engine入門(上)JCConf 2015  - 輕鬆學google的雲端開發 - Google App Engine入門(上)
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)
 
Node js mongodriver
Node js mongodriverNode js mongodriver
Node js mongodriver
 
Hello Swift Final 5/5 - Structures and Classes
Hello Swift Final 5/5 - Structures and ClassesHello Swift Final 5/5 - Structures and Classes
Hello Swift Final 5/5 - Structures and Classes
 
How to Create a l10n Payroll Structure
How to Create a l10n Payroll StructureHow to Create a l10n Payroll Structure
How to Create a l10n Payroll Structure
 
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
 
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
 
MongoDB Indexing Constraints and Creative Schemas
MongoDB Indexing Constraints and Creative SchemasMongoDB Indexing Constraints and Creative Schemas
MongoDB Indexing Constraints and Creative Schemas
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
 
Swift for TensorFlow - CoreML Personalization
Swift for TensorFlow - CoreML PersonalizationSwift for TensorFlow - CoreML Personalization
Swift for TensorFlow - CoreML Personalization
 
Formacion en movilidad: Conceptos de desarrollo en iOS (IV)
Formacion en movilidad: Conceptos de desarrollo en iOS (IV) Formacion en movilidad: Conceptos de desarrollo en iOS (IV)
Formacion en movilidad: Conceptos de desarrollo en iOS (IV)
 
What the FUF?
What the FUF?What the FUF?
What the FUF?
 
The art of reverse engineering flash exploits
The art of reverse engineering flash exploitsThe art of reverse engineering flash exploits
The art of reverse engineering flash exploits
 
Testing javascriptwithjasmine ddd-sydney
Testing javascriptwithjasmine ddd-sydneyTesting javascriptwithjasmine ddd-sydney
Testing javascriptwithjasmine ddd-sydney
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185
 
20120121
2012012120120121
20120121
 

Destaque (8)

Can big data reinvent the credit score?
Can big data reinvent the credit score?Can big data reinvent the credit score?
Can big data reinvent the credit score?
 
Cornerstonefinancialservicesllc
CornerstonefinancialservicesllcCornerstonefinancialservicesllc
Cornerstonefinancialservicesllc
 
Infographic
InfographicInfographic
Infographic
 
12 fatal mistakes LDs make
12 fatal mistakes LDs make12 fatal mistakes LDs make
12 fatal mistakes LDs make
 
Can big data reinvent the credit score?
Can big data reinvent the credit score?Can big data reinvent the credit score?
Can big data reinvent the credit score?
 
Preston International College
Preston International CollegePreston International College
Preston International College
 
Culto das irmãs
Culto das irmãsCulto das irmãs
Culto das irmãs
 
Presentación genaro
Presentación genaroPresentación genaro
Presentación genaro
 

Semelhante a Easy undo.key

iOSDevCamp 2011 Core Data
iOSDevCamp 2011 Core DataiOSDevCamp 2011 Core Data
iOSDevCamp 2011 Core DataChris Mar
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++nsm.nikhil
 
Reflex - How does it work?
Reflex - How does it work?Reflex - How does it work?
Reflex - How does it work?Rocco Caputo
 
iOS 101 - Xcode, Objective-C, iOS APIs
iOS 101 - Xcode, Objective-C, iOS APIsiOS 101 - Xcode, Objective-C, iOS APIs
iOS 101 - Xcode, Objective-C, iOS APIsSubhransu Behera
 
Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersJoris Verbogt
 
Creating Objects in Python
Creating Objects in PythonCreating Objects in Python
Creating Objects in PythonDamian T. Gordon
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: ServersidenessWebExpo
 
High Performance Core Data
High Performance Core DataHigh Performance Core Data
High Performance Core DataMatthew Morey
 
Pavel kravchenko obj c runtime
Pavel kravchenko obj c runtimePavel kravchenko obj c runtime
Pavel kravchenko obj c runtimeDneprCiklumEvents
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming  with microsoft reactive extensionsUnderstanding reactive programming  with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensionsOleksandr Zhevzhyk
 
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...Chris Adamson
 
C++ nothrow movable types
C++ nothrow movable typesC++ nothrow movable types
C++ nothrow movable typesarvidn
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...Tim Chaplin
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test DriveGraham Lee
 
Python testing using mock and pytest
Python testing using mock and pytestPython testing using mock and pytest
Python testing using mock and pytestSuraj Deshmukh
 
JavaScript 101
JavaScript 101JavaScript 101
JavaScript 101ygv2000
 

Semelhante a Easy undo.key (20)

Ns2 by khan
Ns2 by khan Ns2 by khan
Ns2 by khan
 
iOSDevCamp 2011 Core Data
iOSDevCamp 2011 Core DataiOSDevCamp 2011 Core Data
iOSDevCamp 2011 Core Data
 
Reactive x
Reactive xReactive x
Reactive x
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++
 
Reflex - How does it work?
Reflex - How does it work?Reflex - How does it work?
Reflex - How does it work?
 
iOS 101 - Xcode, Objective-C, iOS APIs
iOS 101 - Xcode, Objective-C, iOS APIsiOS 101 - Xcode, Objective-C, iOS APIs
iOS 101 - Xcode, Objective-C, iOS APIs
 
Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web Developers
 
Creating Objects in Python
Creating Objects in PythonCreating Objects in Python
Creating Objects in Python
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: Serversideness
 
High Performance Core Data
High Performance Core DataHigh Performance Core Data
High Performance Core Data
 
Pavel kravchenko obj c runtime
Pavel kravchenko obj c runtimePavel kravchenko obj c runtime
Pavel kravchenko obj c runtime
 
Understanding reactive programming with microsoft reactive extensions
Understanding reactive programming  with microsoft reactive extensionsUnderstanding reactive programming  with microsoft reactive extensions
Understanding reactive programming with microsoft reactive extensions
 
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
 
C++ nothrow movable types
C++ nothrow movable typesC++ nothrow movable types
C++ nothrow movable types
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test Drive
 
Day 2
Day 2Day 2
Day 2
 
Python testing using mock and pytest
Python testing using mock and pytestPython testing using mock and pytest
Python testing using mock and pytest
 
JavaScript 101
JavaScript 101JavaScript 101
JavaScript 101
 
Twins: OOP and FP
Twins: OOP and FPTwins: OOP and FP
Twins: OOP and FP
 

Easy undo.key

  • 1. A How-To for an Easy Undo
  • 2. Last Time • Objective C • Tutorial resources • XCode projects
  • 3. This Time • A simple, common pattern with Cocoa
  • 4. Undo/Redo • You should have undo in your app.
  • 5. The Theory of Undo @interface dot : NSObject { int x; int y; }
  • 6. The Theory of Undo History of X @interface dot : NSObject { • x = 100; int x; int y; }
  • 7. The Theory of Undo History of X @interface dot : NSObject { • x = 100; int x; int y; • x = 22; }
  • 8. The Theory of Undo History of X @interface dot : NSObject { • x = 100; int x; int y; • x = 22; } •x=
  • 9. The Theory of Undo History of X @interface dot : NSObject { int x; x = 22; • int y; } • x = 100; •x=
  • 10. The Theory of Undo History of X x = 22; x = 100; •x=
  • 11. The Theory of Undo Undo Stack x = 22; x = 100; •x=
  • 12. The Theory of Undo Undo Stack x = 22; •x= x = 100;
  • 13. The Theory of Undo Undo Stack x = 22; •x= x = 100;
  • 14. The Theory of Undo Undo Stack x = 22; x= x = 100;
  • 15. The Theory of Undo Undo Stack x = 22; x= x = 100;
  • 16. The Theory of Undo Undo Stack Redo Stack x = 22; x= x = 100;
  • 17. Undo Stack Redo Stack x = 22; x= x = 100;
  • 18. Undo Stack Redo Stack
  • 22. NSUndoManager Q: How many managers?
  • 23. NSUndoManager Q: How many managers? A1: It depends.
  • 24. NSUndoManager Q: How many managers? A1: It depends... A2: ...but often one per doc.
  • 25. NSUndoManager Q: How many managers? A1: It depends... A2: ...but often one per doc. NSDocument
  • 26. NSUndoManager Q: How many managers? A1: It depends... A2: ...but often one per doc. NSDocument eebie # 472: Co coa fr saved arked as un doc m not empty if undo stack
  • 27. Registering Undos 1. Simple Undo 2. Invocation-based Undo
  • 28. Simple Undo [self.document.undoManager registerUndoWithTarget: target selector: aSelector object: anObject];
  • 29. Simple Undo: Example - (void) setX: (int) newX { NSUndoManager undoManager = self.document.undoManager; if (x != newX) { [undoManager registerUndoWithTarget: self selector: @selector(setX:) object: x]; [myObject setX:newX]; } }
  • 30. Simple Undo: Example - (void) setX: (int) newX { NSUndoManager undoManager = self.document.undoManager; if (x != newX) { [undoManager registerUndoWithTarget: self selector: @selector(setX:) object: x]; ject [myObject setX:newX]; } } N ot a n ob
  • 31. Simple Undo: Example - (void) setX: (NSNumber *) newX { NSUndoManager undoManager = self.document.undoManager; if (![x isEqual:newX]) { [undoManager registerUndoWithTarget: self selector: @selector(setX:) object: x]; [myObject setX:newX]; } }
  • 32. Simple Undo: Example - (void) setX: (NSNumber *) newX { NSUndoManager undoManager = self.document.undoManager; if (![x isEqual:newX]) { [undoManager registerUndoWithTarget: self selector: @selector(setX:) object: x]; [myObject setX:newX]; } } Tip: Cocoa uses objects. You usually should too.
  • 33. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>];
  • 34. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; Magic
  • 35. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation Magic
  • 36. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation Magic
  • 37. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation Magic
  • 38. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation • “An action turned into an object.”
  • 39. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation • “An action turned into an object.” • Contains: target, selector, arguments, etc.
  • 40. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation • “An action turned into an object.” • Contains: target, selector, arguments, etc.
  • 41. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; NSInvocation • “An action turned into an object.” • Contains: target, selector, arguments, etc. byte level
  • 42. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens:
  • 43. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens: • Prepare target - “incoming!”
  • 44. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens: • Prepare target - “incoming!” • becomes an NSInvocation <any method> object
  • 45. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens: • Prepare target - “incoming!” • becomes an NSInvocation <any method> object • NSUndoManager doesn’t respond to method> <any
  • 46. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens: • Prepare target - “incoming!” • becomes an NSInvocation <any method> object • NSUndoManager doesn’t respond to method> <any
  • 47. Invocation-based Undo [[undoManager prepareWithInvocationTarget: target] <any method>]; What happens: • Prepare target - “incoming!” • becomes an NSInvocation <any method> object • NSUndoManager doesn’t respond to method> <any • calls with the NSInvocation forwardInvocation:
  • 48. Invocation Undo: Example - (void) setX: (int) newX { NSUndoManager undoManager = self.document.undoManager; if (oldX != newX) { [[undoManager prepareWithInvocationTarget:self] setX:oldX]; [myObject setX:newX]; } }
  • 49. Invocation Undo: Example - (void) setX: (int) newX { NSUndoManager undoManager = self.document.undoManager; if (oldX != newX) { [[undoManager prepareWithInvocationTarget:self] setX:oldX]; [myObject setX:newX]; } } OK
  • 51. Undo Details 1. [undoManager setActionName:@”What’s Changing”];
  • 52. Undo Details 1. [undoManager setActionName:@”What’s Changing”]; 2. Memory management: what’s going on?
  • 53. Undo Details 1. [undoManager setActionName:@”What’s Changing”]; 2. Memory management: what’s going on? • Simple - retains object, not target
  • 54. Undo Details 1. [undoManager setActionName:@”What’s Changing”]; 2. Memory management: what’s going on? • Simple - retains object, not target • Invocation - Probably retained?
  • 55. Undo Details 1. [undoManager setActionName:@”What’s Changing”]; 2. Memory management: what’s going on? • Simple - retains object, not target • Invocation - Probably retained? 3. Undo groupings
  • 56. Undo Architecture • How do we make sure all changes are captured? • Parallel controller objects? • ...that gets repetitive...
  • 59. Key/Value * Observation (K (the basics)
  • 60.
  • 61. K VO: What is it? • Built into base NSObject
  • 62. K VO: What is it? • Built into base NSObject • Automated notifications of property changes
  • 63. K VO: What is it? • Built into base NSObject • Automated notifications of property changes... • ...but allows for manual override
  • 64.
  • 65. K VO: What’s a key? • A string that identifies a property
  • 66. K VO: What’s a key? • A string that identifies a property • e.g. via an accessor method or instance variable
  • 67. K VO: What’s a key? • A string that identifies a property • e.g. via an accessor method or instance variable These accessors... - (void) setHeight: (NSNumber *) newHeight; - (NSNumber *) height;
  • 68. K VO: What’s a key? • A string that identifies a property • e.g. via an accessor method or instance variable These accessors... ...correspond to this key. - (void) setHeight: (NSNumber *) newHeight; @"height" - (NSNumber *) height;
  • 69.
  • 70. K VO: How to use it. 1. Must be KVO compliant for properties you want to observe
  • 71. K VO: How to use it. 1. Must be KVO compliant for properties you want to observe 2. Must register for each property
  • 72. K VO: How to use it. 1. Must be KVO compliant for properties you want to observe 2. Must register for each property 3. Observer must handle the notification
  • 73.
  • 74. 1. K VO Compliance Depends on what kind of property. • To-one • To-many (indexed) • To-many (unordered)
  • 75. 1. K VO Compliance Depends on what kind of property: e.g. - (void • To-one ) setHe - (NSNu ight: ( mber *) NSNumbe height; r *) ne wHeight ; • To-many (indexed) • To-many (unordered)
  • 76. 1. K VO Compliance Depends on what kind of property: e.g. - (void • To-one ) setHe - (NSNu ight: ( mber *) NSNumbe height; r *) ne wHeight ; • To-many (indexed) • To-many (unordered) - (NSUI e.g. - (NSEn - (id) nteger) umerato countOf r *) en MySet; memberO umerato fMySet: rOfMySe (id) an t; Object;
  • 77.
  • 78. 2. K VO Registration [object addObserver: (NSObject *) anObserver forKeyPath: (NSString *) keyPath options: (NSKeyValueObservingOptions) options context: (void *) context];
  • 79.
  • 80. 3. K VO Notifications - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context
  • 81. 3. K VO Notifications - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context { int kindOfChange = [[change objectForKey:NSKeyValueChangeKindKey] intValue]; id oldValue = [change objectForKey:NSKeyValueChangeOldKey]; id newValue = [change objectForKey:NSKeyValueChangeNewKey]; NSIndexSet *indexSet = [change objectForKey:NSKeyValueChangeIndexesKey]; ...

Notas do Editor