undo redo issues with CGLayer

I am working with unod redo operations on CgLayer, I have tried some code, but not able to get it working, dont know , where I am getting wrong, below is my code, which i have written

this is my drawRect function

  • iOS 8 - Screen blank after dismissing view controller with custom presentation
  • dyld: Library not loaded different behavior for 6.0 simulator/6.0 device
  • How do I enter RGB values into Interface Builder?
  • Bug in XCode debugger?
  • Displacing one view with another with a custom segue animation?
  • Return a list of running background apps/processes in iOS
  • - (void)drawRect:(CGRect)rect
    {    
        m_backgroundImage = [UIImage imageNamed:@"bridge.jpg"];
    
        CGPoint drawingTargetPoint = CGPointMake(0,0);
        [m_backgroundImage drawAtPoint:drawingTargetPoint];
    
    
        switch(drawStep)
        {
              case DRAW:
              {
                  CGContextRef context = UIGraphicsGetCurrentContext();
    
                  if(myLayerRef == nil)
                  {
    
                      myLayerRef = CGLayerCreateWithContext(context, self.bounds.size, NULL);
                  }   
    
                  CGContextDrawLayerAtPoint(context, CGPointZero, myLayerRef); 
                  break;
              }           
    
             case UNDO:
             {            
                  [curImage drawInRect:self.bounds];              
                  break;
             }
    
            default:
                break;
        }      
    }
    

    On touches ended , I am converting the layer into NSValue and storing as keyValue pair into NSDictionary and then adding the dictionary object to array.

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {        
        NSValue *layerCopy = [NSValue valueWithPointer:myLayerRef];
    
    
        NSDictionary *lineInfo = [NSDictionary dictionaryWithObjectsAndKeys:layerCopy, @"IMAGE",
                                  nil];
    
        [m_pathArray addObject:lineInfo];    
        NSLog(@"%i",[m_pathArray count]);
    
    }
    

    below is my Undo functionality

    - (void)undoButtonClicked
    {   
        if([m_pathArray count]>0)
        {
            NSMutableArray *_line=[m_pathArray lastObject];
            [m_bufferArray addObject:[_line copy]];
            [m_pathArray removeLastObject];
            drawStep = UNDO;
            [self redrawLine];
        } 
    }
    
    //Redraw functions
    
    - (void)redrawLine
    {
        NSDictionary *lineInfo = [m_pathArray lastObject];
    
        NSValue *val = [lineInfo valueForKey:@"IMAGE"];
    
        CGLayerRef  layerToShow = (CGLayerRef) [val pointerValue];
    
        CGContextRef context1 = CGLayerGetContext(layerToShow);
        CGContextDrawLayerAtPoint(context1, CGPointMake(00, 00),layerToShow);
        [self setNeedsDisplayInRect:self.bounds];
    }
    

    I think its here where I am goin wrong. So friends please help me out.

    From the comments below, I have added the function, where its draws into Cglayer(this function I am calling into touchesMovedEvent.

    - (void) drawingOperations
    {    
        CGContextRef context1 = CGLayerGetContext(myLayerRef);    
    
        CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2); 
        CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1);     
    
        CGContextMoveToPoint(context1, mid1.x, mid1.y);
        CGContextAddQuadCurveToPoint(context1, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y); 
        CGContextSetLineCap(context1, kCGLineCapRound);
        CGContextSetLineWidth(context1, self.lineWidth);
        CGContextSetStrokeColorWithColor(context1, self.lineColor.CGColor);           
        CGContextSetAllowsAntialiasing(context1, YES);
        CGContextSetInterpolationQuality(context1, kCGInterpolationHigh); 
        CGContextSetAlpha(context1, self.lineAlpha);
        CGContextStrokePath(context1);    
    }
    

    Regards
    Ranjit

    2 Solutions Collect From Internet About “undo redo issues with CGLayer”

    The best way to implement Undo and Redo is to implement NSUndoManager as a brief description of it you don’t have to save each state of Object that you want to undo or redo the NSUndoManager itself make this for you …

    Steps for reaching this is:

    1- Initialize NSUndoManager.

    2- Register Object state in the NSUndoManager object with specified function call will discuss this for you case later.

    3-use undo or redo or clear actions function in NSUndoManager Object.

    Ex from my working solution

    -in .h file

    @property (nonatomic,retain) NSUndoManager *undoManager;
    
    • in .m file

      @synthesize undoManager;

    • in “viewDidLoad” method — initialize your NSUndoManager

      undoManager = [[NSUndoManager alloc] init];

    Suppose that you have a function in your class that zoom in/out using pinch so in your “viewDidLoad” you will have

    UIPinchGestureRecognizer *pinchGesture =
        [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
        pinchGesture.delegate = (id)self;
        [self.view addGestureRecognizer:pinchGesture];
    

    So pinch will zoom in/out such
    Note that “MyImageView” is the image that we want to zoom in/out

    - (void)pinch:(UIPinchGestureRecognizer*)recognizer{
    
        if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateChanged) {
            NSLog(@"gesture.scale = %f", recognizer.scale);
    
            CGFloat currentScale = self.MyImageView.frame.size.width / self.MyImageView.bounds.size.width;
            CGFloat newScale = currentScale * recognizer.scale;
            //Here is the line that register image to NSUndoManager before making and adjustments to the image "save current image before changing the transformation"
            //Add image function is function that fired when you Make undo action using NSUndoManager "and so we maintain only image transformation that changed when you zoom in/out"
             [[undoManager prepareWithInvocationTarget:self] AddImage:self.MyImageView.transform];
    
            if (newScale < 0.5) {
                newScale = 0.5;
            }
            if (newScale > 5) {
                newScale = 5;
            }
    
            CGAffineTransform transform = CGAffineTransformMakeScale(newScale, newScale);
            self.MyImageView.transform = transform;
            recognizer.scale = 1;
        }
    }
    

    -AddImage Function will save current image transformation state in NSUndoManager.

    -(void)AddImage:(CGAffineTransform)sender{
        CGAffineTransform transform = sender;
        self.MyImageView.transform = transform;
    }
    

    So if you have button that make Undo action

    -(IBAction)OptionsBtn:(id)sender{
      if ([undoManager canUndo]) {
          [undoManager undo];
      }
    }
    

    So if you want to cancel all action you have both ways

    while ([undoManager canUndo]) {
       [undoManager undo];
    }
    

    OR

    [undoManager removeAllActions];
    
    • (void)redrawLine
      {
      NSDictionary *lineInfo = [m_pathArray lastObject];

      NSValue *val = [lineInfo valueForKey:@”IMAGE”];

      CGContextRef context1 = (CGContextRef) [val pointerValue];
      CGContextDrawLayerAtPoint(context1, CGPointMake(00, 00),layerToShow);
      [self setNeedsDisplayInRect:self.bounds];
      }

    just update this method with ur code