سؤال

I have a very intriguing obstacle to overcome. I am trying to display the live contents of a UIView in another, separate UIView.

What I am trying to accomplish is very similar to Mission Control in Mac OS X. In Mission Control, there are large views in the center, displaying the desktop or an application. Above that, there are small views that can be reorganized. These small views display a live preview of their corresponding app. The preview is instant, and the framerate is exact. Ultimately, I am trying to recreate this effect, as cheaply as possible.

I have tried many possible solutions, and the one shown here is as close as I have gotten. It works, however the - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx method isn't called on every change. My solution was to call [cloneView setNeedsDisplay] using a CADisplayLink, so it is called on every screen refresh. It is very near my goal, but the framerate is extremely low. I think that [CALayer renderInContext:] is much too slow.

If it is possible to have two CALayers render the same source, that would be golden. However, I am not sure how to approach this. Luckily, this is simply a concept app and isn't destined for the App Store, so I can make use of the private APIs. I have looked into IOSurface and Quartz contexts, but I haven't been able to solve this puzzle so far. Any input would be greatly appreciated!

هل كانت مفيدة؟

المحلول

iOS and OSX are actually mostly the same underneath at the lowest level. (However, when you get higher up the stack iOS is actually largely more advanced than OSX as it is newer and had a fresh start)

However, in this case they both use the same thing (I believe). You'll notice something about Mission Control. It isolates "windows" rather than views. On iOS each UIWindow has a ".contentID" property and CALayerHost can use to make the render server share the render context between the 2 of them (2 layers that is).

So my advice is to make your views separate UIWindows and get native mirroring for free-(ish). (In my experience the CALayerHost takes over the target layers place with the render server and so if both the CALayerHost and the window are visible the window won't be anymore, only the layer host will be (which the way they are used on OSX and iOS isn't a problem).)

So if you are after true mirroring, 2 copies of it, you'll need to resort to the sort of thing you were thinking about.

1 Option for this is to create a UIView subclass that uses https://github.com/yyfrankyy/iOS5.1-Framework-Headers/blob/master/UIKit.framework/UIView-Rendering.h#L12 this UIView private method to get an IOSurface for a target view and then using a CADisplayLink once per second get and draw the surface.

Another option which may work (I'm not sure as I don't know your setup or desired effect) is possibly just to use a CAReplicatorLayer which displays a mirror of a CALayer using the same backing store (very fast and efficient + public stable API).

Sorry I couldn't give you a fixed, "this is the answer reply", but hopefully I've given you enough ideas and possibilities to get started. I've also included some links to things you might find useful to read.

What's the magic behind CAReplicatorLayer?

http://aptogo.co.uk/2011/08/no-fuss-reflections/

http://iphonedevwiki.net/index.php/SBAppContextHostManager

http://iphonedevwiki.net/index.php/SBAppContextHostView

http://iphonedevwiki.net/index.php/CALayerHost

http://iky1e.tumblr.com/post/33109276151/recreating-remote-views-ios5

http://iky1e.tumblr.com/post/14886675036/current-projects-understanding-ios-app-rendering

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top