Я думал, что внес свой ответ, чтобы добавить более подробную информацию из Спецификаций.
Во-первых, В чем разница между передачей по ссылке или передачей по значению?
Передача по ссылке означает, что параметр вызываемых функций будет таким же, как переданный аргумент вызывающих (а не значение, а идентификатор - сама переменная).
Передача по значению означает, что параметр вызываемых функций будет копией переданного аргумента вызывающих.
blockquote>Или из википедии, на тему прохода -by-reference
При оценке пошаговой ссылки (также называемой pass-by-reference), функция получает неявную ссылку на переменную, используемую как аргумент, а не копией его стоимости. Это обычно означает, что функция может изменять (т. Е. Назначать) переменную, используемую как аргумент, - то, что будет видно ее вызывающей стороне.
blockquote>При вызове по умолчанию вычисляется выражение аргумента, и результирующее значение привязывается к соответствующей переменной в функции [...]. Если функция или процедура могут назначать значения своим параметрам, назначается только ее локальная копия [...].
blockquote>Во-вторых, нам нужно знать, что использует Java в своих вызовах метода , Спецификация языка Java указывает
При вызове метода или конструктора (§15.12) значения фактических выражений аргументов инициализируют вновь созданные переменные параметра, каждый из которых объявленный тип перед выполнением тела метода или конструктора.
blockquote>Таким образом, он присваивает (или связывает) значение аргумента соответствующей переменной параметра.
Каково значение аргумента?
Рассмотрим ссылочные типы, спецификация Java Virtual Machine Specification
Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. Их значения - это ссылки на динамически созданные экземпляры классов, массивы или экземпляры классов или массивы, которые реализуют интерфейсы соответственно.
blockquote>В спецификации языка Java также указано
Опорные значения (часто только ссылки) являются указателями на эти объекты и специальной нулевой ссылкой, которая ссылается на отсутствие объекта.
blockquote>Значение аргумента ( определенного ссылочного типа) является указателем на объект. Обратите внимание, что переменная, вызов метода с типом возвращаемого типа ссылочного типа и выражение создания экземпляра (
new ...
) все решаются для значения ссылочного типа.Итак
public void method (String param) {} ... String var = new String("ref"); method(var); method(var.toString()); method(new String("ref"));
все связывают значение ссылки с экземпляром
String
с вновь созданным параметром метода,param
. Это именно то, что описывает определение pass-by-value. Таким образом, Java является передачей по значению.Тот факт, что вы можете следовать ссылке для вызова метода или доступа к полю ссылочного объекта, совершенно не имеет отношения к разговору. Определение pass-by-reference было
Это обычно означает, что функция может изменять (т. Е. Присваивать) переменную, используемую как аргумент, - то, что будет видно ее вызывающей стороне.
blockquote>В Java изменение переменной означает ее повторное назначение. В Java, если вы переназначили переменную в методе, она останется незамеченной для вызывающего. Изменение объекта, на которое ссылается переменная, является совершенно другой концепцией.
Примитивные значения также определены в Спецификации виртуальной машины Java, здесь . Значение типа представляет собой соответствующее значение интеграла или с плавающей запятой, соответствующим образом закодированное (8, 16, 32, 64 и т. Д.).
view.snapshotView (afterScreenUpdates: true)
blockquote>
Для удобства я добавил расширение в свой собственный файл
import UIKit
public extension UIWindow {
func capture() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, UIScreen.mainScreen().scale)
self.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
, вызвав расширение следующим образом:
let window: UIWindow! = UIApplication.sharedApplication().keyWindow
let windowImage = window.capture()
Аналогичным образом можно было расширить UIView для захвата образ этого ....
Вместо того, чтобы просто раздавать ответ, позвольте мне объяснить, что делает ваш текущий код и как его модифицировать, чтобы захватить весь экран.
UIGraphicsBeginImageContext(view.frame.size)
Эта строка кода создает новый контекст изображения с тем же размером, что и view
. Главное, чтобы убрать здесь, это то, что новый контекст изображения имеет тот же размер, что и view
. Если вы не хотите захватить версию приложения с низким разрешением (без сетчатки), скорее всего, вы должны использовать UIGraphicsBeginImageContextWithOptions
. Затем вы можете передать 0.0
, чтобы получить тот же масштабный коэффициент, что и основной экран устройства.
view.layer.renderInContext(UIGraphicsGetCurrentContext())
Эта строка кода отобразит слой представления в текущий графический контекст (который является только что созданным вами контекстом). Главное, чтобы отвлечься здесь, состоит в том, что в контекст изображения втягиваются только view
(и его подвид).
let image = UIGraphicsGetImageFromCurrentImageContext()
Эта строка кода создает объект UIImage из того, что было втянуто в графический контекст.
UIGraphicsEndImageContext()
Эта строка кода завершает контекст изображения. Он очищается (вы создали контекст и также должны удалить его.
В результате получается изображение с таким же размером, как view
, с view
и его вложенными в него подзонами .
Если вы хотите нарисовать все в изображении, тогда вы должны создать изображение, которое является размером экрана, и нарисовать на нем все, что на экране. На практике вы, вероятно, просто говорите о все в «ключевом окне» вашего приложения. Поскольку UIWindow
является подклассом UIView
, его можно также вставить в контекст изображения.
UIGraphicsBeginImageContext
, вы увидите, что она называет UIGraphicsBeginImageContextWithOptions
с масштабным коэффициентом 1.0
. Чтение его документации i> сообщит вам, что вы можете установить коэффициент масштабирования на 0.0
таким же, как на главном экране.
– David Rönnqvist
31 July 2015 в 11:10
Я использую этот метод:
func captureScreen() -> UIImage {
var window: UIWindow? = UIApplication.sharedApplication().keyWindow
window = UIApplication.sharedApplication().windows[0] as? UIWindow
UIGraphicsBeginImageContextWithOptions(window!.frame.size, window!.opaque, 0.0)
window!.layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image;
}
Он фиксирует все, кроме строки состояния, и не запрашивает разрешения на сохранение изображений в рулоне камеры.
Hope это помогает!
Расширение Swift 3 для UIWindow
public extension UIWindow {
func capture() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.frame.size, self.isOpaque, UIScreen.main.scale)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}]
Swift 4
/// Takes the screenshot of the screen and returns the corresponding image
///
/// - Parameter shouldSave: Boolean flag asking if the image needs to be saved to user's photo library. Default set to 'true'
/// - Returns: (Optional)image captured as a screenshot
open func takeScreenshot(_ shouldSave: Bool = true) -> UIImage? {
var screenshotImage :UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let image = screenshotImage, shouldSave {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
return screenshotImage
}
Обновлено для Swift 2
Код, который вы предоставляете, работает, но не позволяет вы должны захватить NavigationBar
и StatusBar
на снимке экрана. Если вы хотите сделать снимок экрана вашего устройства, который будет включать в себя NavigationBar
, вы должны использовать следующий код:
func screenShotMethod() {
let layer = UIApplication.sharedApplication().keyWindow!.layer
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
}
С помощью этого кода:
StatusBar
не будет отображаться. touches ended
функции SKScene
– user594883
14 July 2016 в 14:56
Пример Swift 3:
func captureScreen() -> UIImage? {
guard let context = UIGraphicsGetCurrentContext() else { return .none }
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
guard
, добавляет только одну строку
– Martin
2 October 2017 в 15:46
Рекомендуемым способом создания контекста в iOS 10 является использование UIGraphicsImageRenderer
.
extension UIView {
func capture() -> UIImage? {
var image: UIImage?
if #available(iOS 10.0, *) {
let format = UIGraphicsImageRendererFormat()
format.opaque = isOpaque
let renderer = UIGraphicsImageRenderer(size: frame.size, format: format)
image = renderer.image { context in
drawHierarchy(in: frame, afterScreenUpdates: true)
}
} else {
UIGraphicsBeginImageContextWithOptions(frame.size, isOpaque, UIScreen.main.scale)
drawHierarchy(in: frame, afterScreenUpdates: true)
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
return image
}
}
// Full Screen Shot function. Hope this will work well in swift.
func screenShot() -> UIImage {
UIGraphicsBeginImageContext(CGSizeMake(frame.size.width, frame.size.height))
var context:CGContextRef = UIGraphicsGetCurrentContext()
self.view?.drawViewHierarchyInRect(frame, afterScreenUpdates: true)
var screenShot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return screenShot
}
Это похоже, надеюсь, это поможет кому-то в будущем.
self.view.image() //returns UIImage
Вот решение Swift 3
https://gist.github.com/ nitrag / b3117a4b6b8e89fdbc12b98029cf98f8
Xcode 9.3, Swift 4.1
Протестировано на iOS: 9, 10, 11
import UIKit
extension UIApplication {
var screenShot: UIImage? {
return keyWindow?.layer.screenShot
}
}
extension CALayer {
var screenShot: UIImage? {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
if let context = UIGraphicsGetCurrentContext() {
render(in: context)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return screenshot
}
return nil
}
}
imageView.image = UIApplication.shared.screenShot
Xcode 8.2.1, swift 3
import UIKit
extension UIApplication {
var screenShot: UIImage? {
if let layer = keyWindow?.layer {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
if let context = UIGraphicsGetCurrentContext() {
layer.render(in: context)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return screenshot
}
}
return nil
}
}
Если вы попытаетесь использовать код версии 1 в iOS 9x, у вас будет ошибка: CGImageCreateWithImageProvider: поставщик недопустимого изображения: NULL.
blockquote >import UIKit extension UIApplication { var screenShot: UIImage? { if let rootViewController = keyWindow?.rootViewController { let scale = UIScreen.main.scale let bounds = rootViewController.view.bounds UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale); if let _ = UIGraphicsGetCurrentContext() { rootViewController.view.drawHierarchy(in: bounds, afterScreenUpdates: true) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } } return nil } }
Использование
let screenShot = UIApplication.shared.screenShot!