I've got a Mac project I'm working on that required a scalable viewport into another view.  Because the viewport could be a scaled version of the target view, it also needs to be scrollable.  This sort of pattern is seen a lot in editing applications and web browsers.  Specifically, I was looking to mimic the iPhone Simulator app.  It took me about 10 hours of wrangling cocoa to get it to do what I wanted.  I tried writing a custom NSClipView among other tactics, but what I found to work in the end was pretty simple.  This technique should transfer to iOS readily.

To scale the view you're inspecting, you'll likely use NSView's scaleUnitSquareToSize: selector.  This will render the view's contents using Quartz scaling algorithms.  However, it will not change the frame/bounds of the view.  This is where the crux of the problem lies - the scroll extents of the scroll view would not change.  When scaled up, the scroll view would not scroll enough of the view to see all of it.  When scaled down, the scroll view would scroll too far and show emptiness on the sides of the document.

To work around this, we will create a new document view that advertises the correct frame to the scroll view.  It will host the true document view as a subview, without clipping it and without autoresize enabled.  It will monitor the document view's frame and adjust accordingly.  It will also need to know the scale of the document view, and the easiest way to handle that is to have this new host view control the scale of the document.  Here's all the code you need:

@interface HostView : NSView {
  NSView *_docView;
  CGFloat _scale;
}

@property (assign) CGFloat scale;

@end



@implementation HostView

@synthesize scale=_scale;

- (void)updateFrame {
  NSRect frame = _docView.frame;

  // When in landscape mode, flip around the width/height.
  if ([_docView frameRotation] == 90.) {
    CGFloat t = frame.size.width;
    frame.size.width = frame.size.height;
    frame.size.height = t;
  }

  frame.size.width = frame.size.width * _scale;
  frame.size.height = frame.size.height * _scale;
  self.frame = frame;
}

- (void)setScale:(CGFloat)f {
  CGFloat s = f / _scale;
  [docView scaleUnitSquareToSize:NSMakeSize(s, s)];
  _scale = f;
  [self updateFrame];
}

- (void)setOrientation:(BOOL)landscape {
  CGFloat rotationDegrees = 0.;

  // When asked for landscape orientation, rotate counter-clockwise 90 degrees.
  if (landscape) {
    rotationDegrees = 90.;
  }

  // Rotate the document view.  This will generate a frame changed notification
  // that comes back to this object.  The updateFrame: selector will get run to
  // change the document frame.  This will eventually allow the scroll view in
  // which this view is hosted to recalculate its scroll extents.
  [_docView setFrameCenterRotation:rotationDegrees];

  // Oddly, rotation adjusts the frame but not by enough to accommodate a scroll
  // view correctly.  Adjust the frame ourselves.
  NSRect frame = _docView.frame;
  frame.origin = NSZeroPoint;
  if (rotationDegrees == 90.) {
    frame.origin.x = frame.size.height;
  }
  _docView.frame = frame;

  [self setNeedsDisplay:YES];
}

- (void)documentFrameChanged:(NSNotification *)n {
  [self updateFrame];
}

- (void)initWithDocumentView:(NSView *)docView {
  _scale = 1.0;
  _docView = [docView retain];

  [self addSubview:_docView];
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentFrameChanged:) name:NSViewFrameDidChangeNotification object:_docView];

  [self updateFrame];
}

- (void)dealloc {
  [_docView release];
  [super dealloc];
}

@end

Once you have this code, you can call setDocumentView: on any scroll view with a HostView.  When you need to change the scale, call setScale: (or use the property accessor) on the HostView.  The scroll view will adjust its scroll bars accordingly.

Note, however, that the scroll view's frame will not change - the scroll view's size will be the same, but the scroll bars will reflect the correct amount of data that is visible.  If you want the scroll view to adjust its size correctly to fit the document, you will need to add some more monitoring to the document's frame size and adjust accordingly outside of the scroll view itself.

~s