2016-02-03 1 views
11

は、現在のデバイスの画面のUIImageスナップショットを返すプライベートC関数_UICreateScreenUIImageを、考えてみましょうそう:アクセス専用のUIKit機能

MyAppのブリッジング・HEADER.H

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

MyClass.swift

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

ブリッジヘッダーを使用せずに純粋なSwiftで_UICreateScreenUIImageにアクセスできる方法はありますか?

初期の思想がUIImageの拡張機能を作成することでしたが、拡張子が拡張に関数の本体を宣言するために私を期待している:_UICreateScreenUIImageがないよう

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

この実装は、とにかく欠陥があります方法はUIImageです。

純粋なSwiftでもこの方法を公開してアクセスできますか?


「スクリーンショットを撮るにはどうすればよいですか」と私の質問を混同しているようです。それは私が求めていることではありません。私はSwiftのUIImage *_UICreateScreenUIImage(void);のようなメソッドにどうやってアクセスすればよいかを尋ねています。 +(UIImage *)_deviceSpecificImageNamed:(NSString *)name inBundle:(NSBundle *)bundle;または+(UIImage *)_pu_PhotosUIImageNamed:(NSString *)name; のようなプライベートメソッドである可能性があります。

答えて

14

それはあなたが期待するよりもはるかに簡単です:

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

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

偶然にも、@asmnameが実際にがちょうど 2.3に変更された@_silgen_nameに構築し、これに応じて調整する準備ができて:

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

私の知るところでは、@_silgen_nameはObjective-Cメソッドの解決法を提供していません。このため、evenmore強力なObjective-Cのランタイム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を使用して、便利な関数にラップすることができます。

+1

これは機能します。素晴らしい! 'asmname'と' _silgen_name'はどこに文書化されていますか?これはSwiftの「extern C」と同じですか? – JAL

+2

私の知る限りでは(LLVMの内部の外には私は確信しています)。 「asmname」という用語は、他の場所でシンボルを探すようにアセンブラに指示するという意味で、実際には「extern」と同等であることを示します。 '_silgen_name'は、より具体的には、SIL生成の間に' builtin ""() '宣言を生成することを意味します(これはアセンブラによって' extern'に似ています)。 –

+2

ありがとうございました!私はこれを受け入れたものとしてマークし、あなたに恩恵を授与することを期待しています。もう一つの質問です: 'UIImage * _ pu_PhotosUIImageNamed:(NSString *)name;'のような 'UIImage'のプライベートクラスメソッドにアクセスしたいのですが?それは同じパターンに従うでしょうか? – JAL

関連する問題