ios - NullSafe 的原理是什么?
伊谢尔伦
伊谢尔伦 2017-04-17 17:58:07
0
2
565

再nullsafe的github界面里,它的介绍是:

NullSafe is a simple category on NSNull that returns nil for
unrecognised messages instead of throwing an exception.
看了源码始终不得要领。有哪位能帮忙说说其中原理?

#import <objc/runtime.h>
#import <Foundation/Foundation.h>


#ifndef NULLSAFE_ENABLED
#define NULLSAFE_ENABLED 1
#endif


#pragma GCC diagnostic ignored "-Wgnu-conditional-omitted-operand"


@implementation NSNull (NullSafe)

#if NULLSAFE_ENABLED

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    @synchronized([self class])
    {
        //look up method signature
        NSMethodSignature *signature = [super methodSignatureForSelector:selector];
        if (!signature)
        {
            //not supported by NSNull, search other classes
            static NSMutableSet *classList = nil;
            static NSMutableDictionary *signatureCache = nil;
            if (signatureCache == nil)
            {
                classList = [[NSMutableSet alloc] init];
                signatureCache = [[NSMutableDictionary alloc] init];
                
                //get class list
                int numClasses = objc_getClassList(NULL, 0);
                Class *classes = (Class *)malloc(sizeof(Class) * (unsigned long)numClasses);
                numClasses = objc_getClassList(classes, numClasses);
                
                //add to list for checking
                NSMutableSet *excluded = [NSMutableSet set];
                for (int i = 0; i < numClasses; i++)
                {
                    //determine if class has a superclass
                    Class someClass = classes[i];
                    Class superclass = class_getSuperclass(someClass);
                    while (superclass)
                    {
                        if (superclass == [NSObject class])
                        {
                            [classList addObject:someClass];
                            break;
                        }
                        [excluded addObject:NSStringFromClass(superclass)];
                        superclass = class_getSuperclass(superclass);
                    }
                }

                //remove all classes that have subclasses
                for (Class someClass in excluded)
                {
                    [classList removeObject:someClass];
                }

                //free class list
                free(classes);
            }
            
            //check implementation cache first
            NSString *selectorString = NSStringFromSelector(selector);
            signature = signatureCache[selectorString];
            if (!signature)
            {
                //find implementation
                for (Class someClass in classList)
                {
                    if ([someClass instancesRespondToSelector:selector])
                    {
                        signature = [someClass instanceMethodSignatureForSelector:selector];
                        break;
                    }
                }
                
                //cache for next time
                signatureCache[selectorString] = signature ?: [NSNull null];
            }
            else if ([signature isKindOfClass:[NSNull class]])
            {
                signature = nil;
            }
        }
        return signature;
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:nil];
}

#endif

@end
伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全員に返信(2)
洪涛

この図書館のことは知らなかったので、少し調べてみました。
簡単に言うと、NSNull オブジェクトにメッセージを送信するとクラッシュする可能性がありますが (null にはメモリがあるため)、nil にメッセージを送信するとクラッシュしません。
作成者は、このような原則を使用して、NSNull では処理できないメッセージを NSNull に送信し、次の手順で処理します。

  1. メソッド キャッシュを作成します。これにより、プロジェクト内のクラスのすべてのクラス名がキャッシュされます。

  2. キャッシュをループして、このメソッドを実行できるクラスがすでに存在するかどうかを確認します。

  3. 存在する場合は、この NSMethodSignature を返します。

  4. そうでない場合は nil を返し、forwardInvocation: メソッドが使用されます。

  5. [invocation invokeWithTarget:nil];メッセージを nil に転送します。

では、OC では、システムがインスタンスにメッセージを送信し、インスタンス (およびその親クラス) がそれを処理できない場合 (たとえば、そのようなメソッドが存在しないなど)、NSNull がこのメッセージを処理できないと判断するにはどうすればよいでしょうか。 )、システムは methodSignatureForSelector メッセージを送信します。このメソッドが空でない場合は、返されたメソッドを実行します。nil の場合は、forwardInvocation メッセージを送信します。

これで転送チェーン全体が完了します。

余談:
一般的に言えば、プロジェクトでは NSNull クラスを使用すべきではありません (ほとんどの NSNull クラスのソースはインターフェイスの戻り値から得られます)。nil を使用する場合は、ソースをブロックする必要があります。処理のために null に解析するか、サーバーに null を返さないように指示します)。

いいねを押す +0
小葫芦

説明がとてもわかりやすい 66666

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!