私のアプリの大部分は、ネイティブ実装ではまだ利用できない機能を提供するWebビューで構成されています。Webチームは、Webサイトにダークテーマを実装する予定はありません。そのため、私のアプリは、iOS 13のダークモードをサポートすることで少し半分に見えます。
ダークモードのサポートをオプトアウトして、アプリが常にライトモードを表示してWebサイトのテーマに一致するようにすることはできますか?
私のアプリの大部分は、ネイティブ実装ではまだ利用できない機能を提供するWebビューで構成されています。Webチームは、Webサイトにダークテーマを実装する予定はありません。そのため、私のアプリは、iOS 13のダークモードをサポートすることで少し半分に見えます。
ダークモードのサポートをオプトアウトして、アプリが常にライトモードを表示してWebサイトのテーマに一致するようにすることはできますか?
回答:
まず、ダークモードのオプトアウトに関するAppleのエントリです。 このリンクのコンテンツは、Xcode 11およびiOS 13向けに記述されています。
アプリケーション全体をオプトアウトしたい場合
info.plistファイルで次のキーを使用します。
UIUserInterfaceStyle
そして、それに値を割り当てますLight
。
XMLのためのUIUserInterfaceStyle
割り当て:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
overrideUserInterfaceStyle
アプリのwindow
変数に対して設定できます。
プロジェクトの作成方法に応じて、これはAppDelegate
ファイルまたはにありSceneDelegate
ます。
if #available(iOS 13.0, *) {
window?.overrideUserInterfaceStyle = .light
}
UIViewControllerを個別にオプトアウトしたい場合
override func viewDidLoad() {
super.viewDidLoad()
// overrideUserInterfaceStyle is available with iOS 13
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
}
overrideUserInterfaceStyleに関するAppleのドキュメント
上記のコードがXcode 11でどのように見えるか:
提出にXcode 11を使用している場合は、この行の下のすべてを安全に無視できます。
関連するAPIはiOS 12には存在しないため、上記の値を使用しようとするとエラーが発生します。
設定のためのoverrideUserInterfaceStyle
あなたにUIViewController
UIViewControllerを個別にオプトアウトしたい場合
これは、コンパイラバージョンとiOSバージョンをテストすることにより、Xcode 10で処理できます。
#if compiler(>=5.1)
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
#endif
アプリケーション全体をオプトアウトしたい場合
上記のスニペットを変更して、Xcode 10のアプリケーション全体に対して機能するようにするには、AppDelegate
ファイルに次のコードを追加します。
#if compiler(>=5.1)
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
window?.overrideUserInterfaceStyle = .light
}
#endif
ただし、Xcodeバージョン10.xを使用すると、plist設定は失敗します。
功績@Aronネルソン、@Raimundas Sakalauskas、 @NSLeaderとrmaddy彼らのフィードバックと、この答えを改善するため。
overrideUserInterfaceStyle
する代わりにviewDidLoad
、アプリのメインウィンドウで一度設定できます。アプリ全体を一方向に動作させたい場合は、はるかに簡単です。
#if compiler(>=5.1)
代わりに、responds(to:)
とsetValue
「iOSの実装ダークモード」でのAppleのセッションによると(https://developer.apple.com/videos/play/wwdc2019/214/は 31:13から始まる)には、設定することが可能であるoverrideUserInterfaceStyle
にUIUserInterfaceStyleLight
またはUIUserInterfaceStyleDark
任意のビューコントローラやビューに、traitCollection
サブビューまたはビューコントローラので使用されます。
SeanRですでに述べたように、アプリのplistファイルに、またはアプリのplistファイルで設定UIUserInterfaceStyle
して、アプリ全体でこれを変更できます。Light
Dark
Xcode 11以降(つまり、iOS 13以降のSDK)を使用していない場合、アプリはダークモードのサポートを自動的に選択していません。したがって、ダークモードをオプトアウトする必要はありません。
Xcode 11以降を使用している場合、システムはアプリのダークモードを自動的に有効にします。好みに応じて、ダークモードを無効にする2つの方法があります。完全に無効にすることも、特定のウィンドウ、ビュー、またはビューコントローラーに対して無効にすることもできます。
アプリのダークモードを完全に無効にする
アプリのInfo.plistファイルのUIUserInterfaceStyle
ようLight
に、値を含むキーを含めることで、ダークモードを無効にできます。
これはユーザーの設定を無視し、常にアプリに明るい外観を適用します。
ウィンドウ、ビュー、またはビューコントローラーのダークモードを無効にする
overrideUserInterfaceStyle
適切なウィンドウ、ビュー、またはビューコントローラーのプロパティを設定することで、インターフェイスを常に明るいスタイルまたは暗いスタイルで表示させることができます。
ビューコントローラ:
override func viewDidLoad() {
super.viewDidLoad()
/* view controller’s views and child view controllers
always adopt a light interface style. */
overrideUserInterfaceStyle = .light
}
ビュー:
// The view and all of its subviews always adopt light style.
youView.overrideUserInterfaceStyle = .light
窓:
/* Everything in the window adopts the style,
including the root view controller and all presentation controllers that
display content in that window.*/
window.overrideUserInterfaceStyle = .light
注:Appleでは、アプリでダークモードをサポートすることを強くお勧めしています。そのため、ダークモードは一時的にのみ無効にできます。
詳細はこちら:iOSアプリの特定のインターフェイススタイルの選択
********** Xcode 11以降の最も簡単な方法***********
これを前にinfo.plistに追加します </dict></plist>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
私は解決策を見つけたと思います。最初はUIUserInterfaceStyle-Information Property ListとUIUserInterfaceStyle-UIKitから組み合わせましたが、iOSアプリの特定のインターフェイススタイルの選択で実際に文書化されていることがわかりました。
でinfo.plist
、UIUserInterfaceStyle
(User Interface Style)を1(UIUserInterfaceStyle.light
)に設定します。
編集:ドービートルの答えによると、のより適切な設定はUIUserInterfaceStyle
かもしれませんLight
。
[UIInterfaceStyle] '2' is not a recognized value for UIUserInterfaceStyle. Defaulting to Light.
上記の答えは、アプリ全体をオプトアウトしたい場合に有効です。UIを備えたlibで作業していて、.plistを編集する余裕がない場合は、コードを使用して行うこともできます。
iOS 13 SDKに対してコンパイルする場合は、次のコードを使用するだけです。
迅速:
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .light
}
Obj-C:
if (@available(iOS 13.0, *)) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
しかしながら、あなたのコードが反対コンパイルしたい場合は、iOSの12 SDKあまりにも(今はまだ最新の安定SDKである)、あなたは、セレクタを使用してに頼る必要があります。セレクター付きのコード:
Swift(XCodeはこのコードの警告を表示しますが、SDK 12にプロパティが存在しないためコンパイルできないため、これが現時点での唯一の方法です):
if #available(iOS 13.0, *) {
if self.responds(to: Selector("overrideUserInterfaceStyle")) {
self.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
Obj-C:
if (@available(iOS 13.0, *)) {
if ([self respondsToSelector:NSSelectorFromString(@"overrideUserInterfaceStyle")]) {
[self setValue:@(UIUserInterfaceStyleLight) forKey:@"overrideUserInterfaceStyle"];
}
}
overrideUserInterfaceStyle
属しているかを指定した方が良いでしょう。
最新アップデート-
Xcode 10.xを使用している場合、デフォルトUIUserInterfaceStyle
はlight
iOS 13.xです。iOS 13デバイスで実行すると、ライトモードでのみ動作します。
UIUserInterfaceStyle
Info.plistファイルにキーを明示的に追加する必要はありません。キーを追加すると、アプリを検証するときにエラーが発生します。
無効なInfo.plistキーです。Payload / AppName.appInfo.plistファイルのキー「UIUserInterfaceStyle」は無効です。
UIUserInterfaceStyle
Xcode 11.xを使用する場合は、Info.plistファイルにのみキーを追加してください。
UIUserInterfaceStyle
キーをplistファイルに追加すると、Appleはリリースビルドを拒否する可能性があります。https://stackoverflow.com/a/56546554/7524146
とにかく、各ViewControllerを明示的に伝えるのは面倒ですself.overrideUserInterfaceStyle = .light
。ただし、この平和なコードをルートwindow
オブジェクトに一度使用できます。
if #available(iOS 13.0, *) {
if window.responds(to: Selector(("overrideUserInterfaceStyle"))) {
window.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
application(application: didFinishLaunchingWithOptions:)
このセレクターはtrue
その初期段階では応答しないため、内部ではこれを実行できないことに注意してください。しかし、後でそれを行うことができます。AppDelegateでUIを自動的に開始する代わりに、アプリでカスタムAppPresenter
またはAppRouter
クラスを使用している場合は、非常に簡単です。
window!.overrideUserInterfaceStyle = .light
あなたはから窓を得ることができます SceneDelegate
viewController.overrideUserInterfaceStyle = .light
あなたはviewController
、viewControllerの中でさえ、任意のものを設定することができます自己
view.overrideUserInterfaceStyle = .light
view
ビュー内でも任意に設定できます自体を
if #available(iOS 13.0, *) { ,,, }
以前のiOSバージョンをサポートしている場合は、使用する必要がある場合があります。
はい、viewDidLoadに次のコードを追加することでスキップできます。
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
私のアプリは現在のところダークモードをサポートしておらず、明るいアプリバーの色を使用しています。次のキーをmyに追加することで、ステータスバーのコンテンツを暗いテキストとアイコンに強制できましたInfo.plist
。
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDarkContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
ここで他の可能な値を見つけてください:https : //developer.apple.com/documentation/uikit/uistatusbarstyle
ダークモードをサポートまたはバイパスするためにアプリで使用できるヒントとコツをいくつか紹介します。
あなたはUIViewControllerのインターフェーススタイルをオーバーライドすることができます
1:overrideUserInterfaceStyle = .dark //ダークモードの場合
2:overrideUserInterfaceStyle = .light //ライトモードの場合
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
overrideUserInterfaceStyle = .light
}
}
単にあなたは新しいキーを追加することができます
UIUserInterfaceStyle
アプリのinfo.plistで、その値をLightまたはDarkに設定します。これにより、アプリのデフォルトスタイルが指定した値に上書きされます。すべてのviewControllerにoverrideUserInterfaceStyle = .lightこの行を追加する必要はありません。info.plistの1行だけです。
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
} else {
// Fallback on earlier versions
}
アプリのライフサイクル中にウィンドウプロパティが変更される可能性があるため、このソリューションを使用します。したがって、「overrideUserInterfaceStyle = .light」の割り当てを繰り返す必要があります。UIWindow.appearance()を使用すると、新しく作成されたUIWindowオブジェクトに使用されるデフォルト値を設定できます。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13.0, *) {
UIWindow.appearance().overrideUserInterfaceStyle = .light
}
return true
}
}
import UIKit
extension UIViewController {
override open func awakeFromNib() {
super.awakeFromNib()
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
}
}
実際、私はアプリケーションのすべてのviwコントローラーをputzすることなく、コードのダークモードをグローバルにオプトアウトできるようにするコードをいくつか書いたところです。これはおそらく、クラスのリストを管理することにより、クラスごとにオプトアウトするように改良できます。私にとって、私が欲しいのは、ユーザーが私のアプリのダークモードインターフェイスを気に入っているかどうかを確認し、ユーザーが気に入らない場合はオフにできることです。これにより、残りのアプリケーションでダークモードを引き続き使用できます。
ユーザーの選択は適切です(Ahem、Appleを見ると、これが実装方法でした)。
これがどのように機能するかは、UIViewControllerの単なるカテゴリであるということです。ロードすると、ネイティブのviewDidLoadメソッドがグローバルフラグをチェックしてダークモードがすべて無効になっているかどうかを確認するメソッドに置き換えられます。
UIViewControllerのロード時にトリガーされるため、デフォルトでダークモードが自動的に起動して無効になります。これが必要なものでない場合は、早期にどこかにアクセスしてフラグを設定するか、デフォルトのフラグを設定する必要があります。
フラグをオンまたはオフにするユーザーに応答するために、まだ何も書いていません。したがって、これは基本的にサンプルコードです。ユーザーがこれを操作できるようにするには、すべてのView Controllerを再ロードする必要があります。私はそれをオフハンドで行う方法を知りませんが、おそらく何らかの通知を送信することでうまくいくでしょう。したがって、現在、このダークモードのグローバルオン/オフは、アプリの起動時または再起動時にのみ機能します。
巨大なアプリのすべてのMFING viewControllerでダークモードをオフにしようとするだけでは十分ではありません。カラーアセットを使用している場合は、完全に骨が折れています。私たちは10年以上にわたり、不変オブジェクトは不変であると理解しています。カラーアセットカタログから取得した色は、UIColorであると言いますが、動的(可変)色であり、システムが暗いモードから明るいモードに変わると、その下で変化します。それが特徴のはずです。ただし、もちろん、これらの変更を停止するように要求するマスター切り替えはありません(私が今知っている限りでは、誰かがこれを改善できるかもしれません)。
したがって、ソリューションは2つの部分に分かれています。
いくつかのユーティリティと便利なメソッドを提供するUIViewControllerのパブリックカテゴリ...たとえば、私たちの一部がアプリにWebコードを混在させるという事実についてAppleが考えていなかったと思います。そのため、ダークモードまたはライトモードに基づいて切り替える必要のあるスタイルシートがあります。したがって、何らかの動的スタイルシートオブジェクトを作成するか(これは良いことです)、または単に現在の状態が何であるかを尋ねる必要があります(悪いが簡単です)。
このカテゴリがロードされると、UIViewControllerクラスのviewDidLoadメソッドが置き換えられ、呼び出しがインターセプトされます。それがアプリストアのルールに違反しているかどうかはわかりません。もしそうなら、おそらく他の方法がありますが、それは概念実証と考えることができます。たとえば、すべてのメインビューコントローラータイプの1つのサブクラスを作成し、すべての独自のビューコントローラーをそれらから継承させることができます。次に、DarkModeカテゴリのアイデアを使用してそれを呼び出し、すべてのビューコントローラーを強制的にオプトアウトできます。それは醜いですが、それはいかなる規則にも違反しません。私はランタイムを使用することを好みます。それは、ランタイムがそうするために作られたものだからです。したがって、私のバージョンでは、カテゴリを追加するだけで、ダークモードをブロックするかどうかに応じて、カテゴリにグローバル変数を設定します。
既に説明したように、あなたはまだ森の外にいません。もう1つの問題は、UIColorが基本的に何をしたいのかということです。したがって、ビューコントローラーがダークモードをブロックしている場合でも、UIColorはそれをどこでどのように使用しているかを認識できないため、適応できません。その結果、あなたはそれを正しくフェッチすることができますが、それは将来のある時点で元に戻るでしょう。多分すぐに多分後で。したがって、その回避策は、CGColorを使用して2回割り当て、静的な色に変換することです。これは、ユーザーが戻って設定ページでダークモードを再度有効にした場合(ここでのアイデアは、ユーザーがシステムの他の部分に加えてアプリを制御できるようにこの機能を動作させることです)、それらすべての静的な色交換が必要です。これまでのところ、これは誰かが解決するために残されています。それを行う簡単なお尻の方法は、あなたがデフォルトを作ることです ダークモードをオプトアウトするには、ゼロで除算してアプリをクラッシュさせ、アプリを終了してユーザーに再起動するように指示することはできないためです。これはおそらくアプリストアのガイドラインにも違反していますが、それはアイデアです。
UIColorカテゴリを公開する必要はありません。colorNamedを呼び出して機能します。... DarkMode ViewControllerクラスにダークモードをブロックするように指示しなかった場合、期待どおりに完全に機能します。標準のリンゴのスファゲッティコードの代わりにエレガントなものを作ろうとすると、プログラムでダークモードをオプトアウトまたはトグルしたい場合、ほとんどのアプリを変更する必要があります。現在、Info.plistをプログラムで変更して、必要に応じてダークモードをオフにするより良い方法があるかどうかはわかりません。私が理解している限り、これはコンパイル時の機能であり、その後は骨の折れる作業です。
したがって、ここに必要なコードがあります。ドロップインし、1つのメソッドを使用してUIスタイルを設定するか、コードでデフォルトを設定する必要があります。あなたは自由に使用、変更、これをどんな目的のためにでも好きなように行うことができ、保証はありません。それがアプリストアを通過するかどうかはわかりません。改善は大歓迎です。
公正な警告ARCやその他の手持ちの方法は使用しません。
////// H file
#import <UIKit/UIKit.h>
@interface UIViewController(DarkMode)
// if you want to globally opt out of dark mode you call these before any view controllers load
// at the moment they will only take effect for future loaded view controllers, rather than currently
// loaded view controllers
// we are doing it like this so you don't have to fill your code with @availables() when you include this
typedef enum {
QOverrideUserInterfaceStyleUnspecified,
QOverrideUserInterfaceStyleLight,
QOverrideUserInterfaceStyleDark,
} QOverrideUserInterfaceStyle;
// the opposite condition is light interface mode
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)override;
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
// utility methods
// this will tell you if any particular view controller is operating in dark mode
- (BOOL)isUsingDarkInterfaceStyle;
// this will tell you if any particular view controller is operating in light mode mode
- (BOOL)isUsingLightInterfaceStyle;
// this is called automatically during all view controller loads to enforce a single style
- (void)tryToOverrideUserInterfaceStyle;
@end
////// M file
//
// QDarkMode.m
#import "UIViewController+DarkMode.h"
#import "q-runtime.h"
@implementation UIViewController(DarkMode)
typedef void (*void_method_imp_t) (id self, SEL cmd);
static void_method_imp_t _nativeViewDidLoad = NULL;
// we can't @available here because we're not in a method context
static long _override = -1;
+ (void)load;
{
#define DEFAULT_UI_STYLE UIUserInterfaceStyleLight
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
_override = DEFAULT_UI_STYLE;
/*
This doesn't work...
NSUserDefaults *d = NSUserDefaults.standardUserDefaults;
[d setObject:@"Light" forKey:@"UIUserInterfaceStyle"];
id uiStyle = [d objectForKey:@"UIUserInterfaceStyle"];
NSLog(@"%@",uiStyle);
*/
if (!_nativeViewDidLoad) {
Class targetClass = UIViewController.class;
SEL targetSelector = @selector(viewDidLoad);
SEL replacementSelector = @selector(_overrideModeViewDidLoad);
_nativeViewDidLoad = (void_method_imp_t)QMethodImplementationForSEL(targetClass,targetSelector);
QInstanceMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// we do it like this because it's not going to be set often, and it will be tested often
// so we can cache the value that we want to hand to the OS
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)style;
{
if (@available(iOS 13,*)){
switch(style) {
case QOverrideUserInterfaceStyleLight: {
_override = UIUserInterfaceStyleLight;
} break;
case QOverrideUserInterfaceStyleDark: {
_override = UIUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH - more modes can go here*/
case QOverrideUserInterfaceStyleUnspecified: {
_override = UIUserInterfaceStyleUnspecified;
} break;
}
}
}
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
{
if (@available(iOS 13,*)){
switch(_override) {
case UIUserInterfaceStyleLight: {
return QOverrideUserInterfaceStyleLight;
} break;
case UIUserInterfaceStyleDark: {
return QOverrideUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH */
case UIUserInterfaceStyleUnspecified: {
return QOverrideUserInterfaceStyleUnspecified;
} break;
}
} else {
// we can't override anything below iOS 12
return QOverrideUserInterfaceStyleUnspecified;
}
}
- (BOOL)isUsingDarkInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark){
return YES;
}
}
return NO;
}
- (BOOL)isUsingLightInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
return YES;
}
// if it's unspecified we should probably assume light mode, esp. iOS 12
}
return YES;
}
- (void)tryToOverrideUserInterfaceStyle;
{
// we have to check again or the compile will bitch
if (@available(iOS 13,*)) {
[self setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)_override];
}
}
// this method will be called via the viewDidLoad chain as we will patch it into the
// UIViewController class
- (void)_overrideModeViewDidLoad;
{
if (_nativeViewDidLoad) {
_nativeViewDidLoad(self,@selector(viewDidLoad));
}
[self tryToOverrideUserInterfaceStyle];
}
@end
// keep this in the same file, hidden away as it needs to switch on the global ... yeah global variables, I know, but viewDidLoad and colorNamed: are going to get called a ton and already it's adding some inefficiency to an already inefficient system ... you can change if you want to make it a class variable.
// this is necessary because UIColor will also check the current trait collection when using asset catalogs
// so we need to repair colorNamed: and possibly other methods
@interface UIColor(DarkMode)
@end
@implementation UIColor (DarkMode)
typedef UIColor *(*color_method_imp_t) (id self, SEL cmd, NSString *name);
static color_method_imp_t _nativeColorNamed = NULL;
+ (void)load;
{
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
if (!_nativeColorNamed) {
// we need to call it once to force the color assets to load
Class targetClass = UIColor.class;
SEL targetSelector = @selector(colorNamed:);
SEL replacementSelector = @selector(_overrideColorNamed:);
_nativeColorNamed = (color_method_imp_t)QClassMethodImplementationForSEL(targetClass,targetSelector);
QClassMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// basically the colors you get
// out of colorNamed: are dynamic colors... as the system traits change underneath you, the UIColor object you
// have will also change since we can't force override the system traits all we can do is force the UIColor
// that's requested to be allocated out of the trait collection, and then stripped of the dynamic info
// unfortunately that means that all colors throughout the app will be static and that is either a bug or
// a good thing since they won't respond to the system going in and out of dark mode
+ (UIColor *)_overrideColorNamed:(NSString *)string;
{
UIColor *value = nil;
if (@available(iOS 13,*)) {
value = _nativeColorNamed(self,@selector(colorNamed:),string);
if (_override != UIUserInterfaceStyleUnspecified) {
// the value we have is a dynamic color... we need to resolve against a chosen trait collection
UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_override];
value = [value resolvedColorWithTraitCollection:tc];
}
} else {
// this is unreachable code since the method won't get patched in below iOS 13, so this
// is left blank on purpose
}
return value;
}
@end
メソッドスワッピングを実行するために使用するユーティリティ関数のセットがあります。別のファイル。これは標準的なものですが、どこでも同じようなコードを見つけることができます。
// q-runtime.h
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <stdatomic.h>
// returns the method implementation for the selector
extern IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector);
// as above but gets class method
extern IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector);
extern BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
extern BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
// q-runtime.m
static BOOL
_QMethodOverride(Class targetClass, SEL targetSelector, Method original, Method replacement)
{
BOOL flag = NO;
IMP imp = method_getImplementation(replacement);
// we need something to work with
if (replacement) {
// if something was sitting on the SEL already
if (original) {
flag = method_setImplementation(original, imp) ? YES : NO;
// if we're swapping, use this
//method_exchangeImplementations(om, rm);
} else {
// not sure this works with class methods...
// if it's not there we want to add it
flag = YES;
const char *types = method_getTypeEncoding(replacement);
class_addMethod(targetClass,targetSelector,imp,types);
XLog_FB(red,black,@"Not sure this works...");
}
}
return flag;
}
BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getInstanceMethod(targetClass,targetSelector);
Method rm = class_getInstanceMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getClassMethod(targetClass,targetSelector);
Method rm = class_getClassMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getInstanceMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getClassMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
q-runtime.hは私の再利用可能なライブラリであり、これはその一部にすぎないため、これをいくつかのファイルからコピーして貼り付けています。コンパイルできないものがある場合はお知らせください。
UIUserInterfaceStyle
しLight
ます。developer.apple.com/library/archive/documentation/General/…を