在不使用桥接头的情况下访问私有 UIKit 函数

Access Private UIKit Function Without Using Bridging Header(在不使用桥接头的情况下访问私有 UIKit 函数)
本文介绍了在不使用桥接头的情况下访问私有 UIKit 函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑私有 C 函数 _UICreateScreenUIImage,它返回当前设备屏幕的 UIImage 快照:

Consider the private C function _UICreateScreenUIImage, which returns a UIImage snapshot of the current device screen:

OBJC_EXTERN UIImage *_UICreateScreenUIImage(void) NS_RETURNS_RETAINED;

我可以把它放在一个桥接头中并像这样在 Swift 中访问它:

I can put this in a bridging header and access it in Swift like so:

MyApp-Bridging-Header.h

MyApp-Bridging-Header.h

@import UIKit;
UIImage *_UICreateScreenUIImage(void) NS_RETURNS_RETAINED;

MyClass.swift

MyClass.swift

let image = _UICreateScreenUIImage()
print(image) // <UIImage: 0x7fc4ba6081c0>, {375, 667}

有没有一种方法可以在不使用桥接头的情况下在纯 Swift 中访问 _UICreateScreenUIImage?

Is there a way I can access _UICreateScreenUIImage in pure Swift without using a bridging header?

最初的想法是在 UIImage 上创建一个扩展,但扩展期望我在扩展中声明函数的主体:

An initial thought was to create an extension on UIImage, but the extension is expecting me to declare the body of the function in the extension:

extension UIImage {
    public func _UICreateScreenUIImage(_: Void) -> UIImage // "Expected '{' in body of function declaration"
}

无论如何,这个实现是有缺陷的,因为 _UICreateScreenUIImage 不是 UIImage 上的方法.

This implementation is flawed anyways, as _UICreateScreenUIImage isn't a method on UIImage.

是否可以在纯 Swift 中公开和访问此方法?

Is exposing and accessing this method possible in pure Swift?

人们似乎将我的问题与我如何截屏?"混淆了.这不是我要问的.我在问如何在 Swift 中访问像 UIImage *_UICreateScreenUIImage(void); 这样的方法.它可以是任何私有方法,例如 +(UIImage *)_deviceSpecificImageNamed:(NSString *)name inBundle:(NSBundle *)bundle;+(UIImage *)_pu_PhotosUIImageNamed:(NSString *)名称;.

People seem to be confusing my question with "How do I take a screenshot?" That's not what I'm asking. I'm asking how do I access methods like UIImage *_UICreateScreenUIImage(void); in Swift. It could be any private method, such as +(UIImage *)_deviceSpecificImageNamed:(NSString *)name inBundle:(NSBundle *)bundle; or +(UIImage *)_pu_PhotosUIImageNamed:(NSString *)name; .

推荐答案

这比你想象的要容易得多:

It's a lot easier than you would expect:

@asmname("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> UIImage

// That's it – go ahead and call it:
_UICreateScreenUIImage()

事实上,@asmname 实际上刚刚在 2.3 版本中被更改为 @_silgen_name,因此请做好相应调整的准备:

As it happens, @asmname has actually just been changed in the 2.3 builds to @_silgen_name, so be ready to adjust accordingly:

@_silgen_name("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> UIImage

据我所知,@_silgen_name 不提供 Objective-C 方法的解析.为此,还有更强大的 Objective-C 运行时 API:

To my knowledge, @_silgen_name does not provide resolution of Objective-C methods. For this, there is the evenmore powerful Objective-C runtime API:

let invokeImageNamed: (String, NSTimeInterval) -> UIImage? = {
    // The Objective-C selector for the method.
    let selector: Selector = "animatedImageNamed:duration:"
    guard case let method = class_getClassMethod(UIImage.self, selector)
        where method != nil else { fatalError("Failed to look up (selector)") }

    // Recreation of the method's implementation function.
    typealias Prototype = @convention(c) (AnyClass, Selector, NSString, NSTimeInterval) -> UIImage?
    let opaqueIMP = method_getImplementation(method)
    let function = unsafeBitCast(opaqueIMP, Prototype.self)

    // Capture the implemenation data in a closure that can be invoked at any time.
    return { name, interval in function(UIImage.self, selector, name, interval) }
}()

extension UIImage {
    // Convenience method for calling the closure from the class.
    class func imageNamed(name: String, interval: NSTimeInterval) -> UIImage? {
        return invokeImageNamed(name, interval)
    }
}

UIImage.imageNamed("test", interval: 0)

就处理 NS_RETURNS_RETAINED 而言,这不会为您生成.相反,您可以使用 Unmanaged 的返回类型,并将其包装在一个函数中以方便您使用:

As far as handling NS_RETURNS_RETAINED, this won't be generated for you. Instead, you can use a return type of Unmanaged, and wrap that in a function to your convenience:

@_silgen_name("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> Unmanaged<UIImage>
func UICreateScreenUIImage() -> UIImage {
    return _UICreateScreenUIImage().takeRetainedValue()
}

这篇关于在不使用桥接头的情况下访问私有 UIKit 函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
iOS VoiceOver functionality changes with Bundle Identifier(IOS画外音功能随捆绑包标识符而变化)
tabbar middle tab out of tabbar corner(选项卡栏中间的选项卡角外)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
How can I sync two flatList scroll position in react native(如何在本机Reaction中同步两个平面列表滚动位置)