मैं अपने app से स्क्रीनशॉट को बचाने की जरूरत में एक CALayer रेंडर करने के लिए कैसे, तो मैं इस तरह कोड है, जो काम करता है की स्थापना की है:पृष्ठभूमि
- (void)renderScreen {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CGSize outputSize = keyWindow.bounds.size;
UIGraphicsBeginImageContext(outputSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CALayer *layer = [keyWindow layer];
[layer renderInContext:context];
CGContextRestoreGState(context);
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// now save the screen image, etc...
}
हालांकि, जब स्क्रीन छवि जटिल (बहुत हो जाता है विचारों के), renderInContext को आईपैड 3 पर 0.8 सेकंड तक लग सकते हैं, और उस समय के दौरान यूजर इंटरफेस लॉक हो जाता है, जो कुछ अन्य कार्यक्षमताओं में हस्तक्षेप करता है।
- (void)renderScreen {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CALayer *layer = [keyWindow layer];
[self performSelectorInBackground:@selector(renderLayer:) withObject:layer];
}
- (void)renderLayer:(CALayer *)layer {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CGSize outputSize = keyWindow.bounds.size;
UIGraphicsBeginImageContext(outputSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
[layer renderInContext:context];
CGContextRestoreGState(context);
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// now save the screen image, etc...
}
इंटरफ़ेस सुचारू रूप से फिर से चलाने के लिए अनुमति देता है, लेकिन कभी-कभी renderInContext लाइन पर EXC_BAD_ACCESS के साथ एक दुर्घटना का कारण बनता है कि: तो मैं एक पृष्ठभूमि धागा करने के लिए प्रतिपादन, इस तरह ले जाया गया। मैंने परत की जांच करने की कोशिश की! = शून्य और [परत प्रतिक्रियाएं चयनकर्ता: @ चयनकर्ता (renderInContext :)] पहले, इसलिए मैं दुर्घटना से बच सकता था, लेकिन दोनों स्थितियां हमेशा सच होती हैं।
फिर मैंने this SO comment पढ़ा, यह बताते हुए कि एक परत पृष्ठभूमि ऑपरेशन से पहले एक परत बदल सकती है और परत की प्रतिलिपि को पृष्ठभूमि ऑपरेशन में भेजने का सुझाव देती है। This SO answer और this one गया मुझे शुरू कर दिया है, और मैं CALayer की एक प्रति विधि जोड़ने के लिए इस श्रेणी के साथ समाप्त हो गया:
#import "QuartzCore/CALayer.h"
@interface CALayer (CALayerCopyable)
- (id)copy;
@end
@implementation CALayer (CALayerCopyable)
- (id)copy {
CALayer *newLayer = [CALayer layer];
newLayer.actions = [self.actions copy];
newLayer.anchorPoint = self.anchorPoint;
newLayer.anchorPointZ = self.anchorPointZ;
newLayer.backgroundColor = self.backgroundColor;
//newLayer.backgroundFilters = [self.backgroundFilters copy]; // iOS 5+
newLayer.borderColor = self.borderColor;
newLayer.borderWidth = self.borderWidth;
newLayer.bounds = self.bounds;
//newLayer.compositingFilter = self.compositingFilter; // iOS 5+
newLayer.contents = [self.contents copy];
newLayer.contentsCenter = self.contentsCenter;
newLayer.contentsGravity = [self.contentsGravity copy];
newLayer.contentsRect = self.contentsRect;
//newLayer.contentsScale = self.contentsScale; // iOS 4+
newLayer.cornerRadius = self.cornerRadius;
newLayer.delegate = self.delegate;
newLayer.doubleSided = self.doubleSided;
newLayer.edgeAntialiasingMask = self.edgeAntialiasingMask;
//newLayer.filters = [self.filters copy]; // iOS 5+
newLayer.frame = self.frame;
newLayer.geometryFlipped = self.geometryFlipped;
newLayer.hidden = self.hidden;
newLayer.magnificationFilter = [self.magnificationFilter copy];
newLayer.mask = [self.mask copy]; // property is another CALayer
newLayer.masksToBounds = self.masksToBounds;
newLayer.minificationFilter = [self.minificationFilter copy];
newLayer.minificationFilterBias = self.minificationFilterBias;
newLayer.name = [self.name copy];
newLayer.needsDisplayOnBoundsChange = self.needsDisplayOnBoundsChange;
newLayer.opacity = self.opacity;
newLayer.opaque = self.opaque;
newLayer.position = self.position;
newLayer.rasterizationScale = self.rasterizationScale;
newLayer.shadowColor = self.shadowColor;
newLayer.shadowOffset = self.shadowOffset;
newLayer.shadowOpacity = self.shadowOpacity;
newLayer.shadowPath = self.shadowPath;
newLayer.shadowRadius = self.shadowRadius;
newLayer.shouldRasterize = self.shouldRasterize;
newLayer.style = [self.style copy];
//newLayer.sublayers = [self.sublayers copy]; // this line makes the screen go blank
newLayer.sublayerTransform = self.sublayerTransform;
//newLayer.superlayer = self.superlayer; // read-only
newLayer.transform = self.transform;
//newLayer.visibleRect = self.visibleRect; // read-only
newLayer.zPosition = self.zPosition;
return newLayer;
}
@end
तब मैं renderScreen अद्यतन renderLayer को परत की एक प्रति भेजने के लिए:
- (void)renderScreen {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CALayer *layer = [keyWindow layer];
CALayer *layerCopy = [layer copy];
[self performSelectorInBackground:@selector(renderLayer:) withObject:layerCopy];
}
जब मैं इस कोड को चलाता हूं, तो सभी स्क्रीन छवियां सादे सफेद होती हैं। जाहिर है मेरी प्रति विधि सही नहीं है। तो क्या कोई मुझे निम्नलिखित संभावित समाधानों में से किसी के साथ मदद कर सकता है?
- कैलियर के लिए एक प्रति विधि कैसे लिखें जो वास्तव में काम करता है?
- यह जांचने के लिए कि पृष्ठभूमि प्रक्रिया में पारित एक परत renderInContext के लिए एक वैध लक्ष्य है?
- इंटरफ़ेस को लॉक किए बिना जटिल परतों को प्रस्तुत करने का कोई अन्य तरीका?
अद्यतन: मैं इन कैथियर कॉपीराइट का उपयोग करने के लिए रोब नेपियर के सुझाव के आधार पर अपनी कैलियर कॉपी करने योग्य श्रेणी को फिर से लिखता हूं। बस परत की प्रतिलिपि बनाकर मुझे एक सादा सफेद आउटपुट दिया गया, इसलिए मैंने सभी सबबेलर्स को दोबारा कॉपी करने के लिए एक विधि जोड़ा। मैं अब भी है, तथापि, सादा सफेद आउटपुट प्राप्त:
#import "QuartzCore/CALayer.h"
@interface CALayer (CALayerCopyable)
- (id)copy;
- (NSArray *)copySublayers:(NSArray *)sublayers;
@end
@implementation CALayer (CALayerCopyable)
- (id)copy {
CALayer *newLayer = [[CALayer alloc] initWithLayer:self];
newLayer.sublayers = [self copySublayers:self.sublayers];
return newLayer;
}
- (NSArray *)copySublayers:(NSArray *)sublayers {
NSMutableArray *newSublayers = [NSMutableArray arrayWithCapacity:[sublayers count]];
for (CALayer *sublayer in sublayers) {
[newSublayers addObject:[sublayer copy]];
}
return [NSArray arrayWithArray:newSublayers];
}
@end
आपका पृष्ठभूमि थ्रेड * * UIWindow' स्पर्श नहीं कर सकता है। आपको आकार को सीधे पास करने की आवश्यकता है। –
ठीक है, धन्यवाद, मेरे तत्काल परीक्षण उद्देश्यों के लिए अब मैं खिड़की के आकार को कड़ी-कोडिंग कर रहा हूं। इस समाधान के आधार पर कि मैं किस समाधान के साथ समाप्त होता हूं, मैं गतिशील रूप से इसे पारित करने का एक अच्छा तरीका समझूंगा। हालांकि, यह मेरी वर्तमान समस्या को प्रभावित नहीं करता है। – arlomedia
क्या आप इसके लिए एक अच्छा समाधान खत्म कर चुके हैं? –