GithubHelp home page GithubHelp logo

jasenhuang / nsobjectsafe Goto Github PK

View Code? Open in Web Editor NEW
591.0 19.0 114.0 84 KB

Swizzle commonly used function of Foundation container to prevent nil crash

Objective-C 100.00%
swizzle crash ios unrecognized-selecto class-cluster nsattributestring

nsobjectsafe's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nsobjectsafe's Issues

objectForKey 没有必要防御

系统 framework 其实在 objectForKey 传 nil 的时候不会 crash,我这边检测到有些时候弹出键盘系统线程自己就会传 nil 进来

跟ReactiveCocoa不兼容

用你这个,ReactiveCocoa就不兼容了,报错

  • (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;
  • (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer;
    不能使用__weak

编译错误

Unknown class name 'NSAttributedStringKey'; did you mean 'NSAttributedString'?

NSObjectSafe crash for iOS8

for iOS9
[[NSArray alloc] init] --> __NSArray0
for iOS8 and lower
[[NSArray alloc] init] --> __NArrayI

so for iOS8 and lower, we don't need to swizzle for two times:
'''
/* 数组有内容obj类型才是__NSArrayI /
NSArray
obj = [[NSArray alloc] initWithObjects:@0, nil];
[obj swizzleInstanceMethod:@selector(objectAtIndex:) withMethod:@selector(hookObjectAtIndex:)];

/* 没内容类型是__NSArray0 */
obj = [[NSArray alloc] init];
[obj swizzleInstanceMethod:@selector(objectAtIndex:) withMethod:@selector(hookObjectAtIndex0:)];
'''

iOS11 使用导航的搜索控制器属性,崩溃

这是一个能稳定复现的崩溃
从页面A 模态弹出 页面B(页面B中使用self.navigationItem.searchController = self.searchController 添加搜索栏)
此时使用该类库会稳定崩溃,打开僵尸对象,控制台打印*** -[UINavigationBar release]: message sent to deallocated instance 0x7fa305303970
若移除该类库则正常
若无法复现我可以上传demo

部分可变类型的类别容易导致数据被截断

例如NSMutableData类别中[hookReplaceBytesInRange:withBytes:],如果有需要替换长度超过原数据长度的情况下,超过长度的数据就被截断,这样的做法容易产生意想不到的后果,希望能再被优化,不是简单地截断后面的数据,其实不截断处理也不会崩溃,不是吗?请尽快想办法优化,已经有开发者遇到此问题了 @jasenhuang @hypoyao @tedzhou

NSCache无需拦截key为空的情况

NSCache进行swizzing交换时,无需判断key为nil的情况,因为setObject:forKey方法里key不遵循NSCoping协议,而且通过本地测试(我用的iOS13)测试,当key为nil时,执行上述set方法不会crash,仍然可以继续执行

Crashed when AirDrop present UIActivityViewController on iOS13.0/Xcode 11

Scene:
UIActivityViewController *shareVC = [[UIActivityViewController alloc]initWithActivityItems:@[self.debugText.string] applicationActivities:nil];
[self presentViewController:shareVC animated:YES completion:nil];

Crash:
crash at NSCache(safe) hookSetObject:forKey: ,because input an nil key, but when I don't use NSObjectSafe , it doesn't crash .

Here is screenshot:
image

使问题

1.进接引入头文件就可以了么
2.如果不报错了,bugly还能收集到错误不

崩溃问题

我添加进去之后,直接崩溃了。该设置的地方也都设置过了,不知道该怎么设置

为啥交换 class method 和交换 instance method 的实现有差异?

+ (void)swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Class cls = [self class];
    
    Method originalMethod = class_getClassMethod(cls, origSelector);
    Method swizzledMethod = class_getClassMethod(cls, newSelector);
    
    Class metacls = objc_getMetaClass(NSStringFromClass(cls).UTF8String);
    if (class_addMethod(metacls,
                        origSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod)) ) {
        /* swizzing super class method, added if not exist */
        class_replaceMethod(metacls,
                            newSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
        
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
- (void)swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Class cls = [self class];
    /* if current class not exist selector, then get super*/
    Method originalMethod = class_getInstanceMethod(cls, origSelector);
    Method swizzledMethod = class_getInstanceMethod(cls, newSelector);
    /* add selector if not exist, implement append with method */
    if (class_addMethod(cls,
                        origSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod)) ) {
        /* replace class instance method, added if selector not exist */
        /* for class cluster , it always add new selector here */
        class_replaceMethod(cls,
                            newSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
        
    } else {
        /* swizzleMethod maybe belong to super */
        class_replaceMethod(cls,
                            newSelector,
                            class_replaceMethod(cls,
                                                origSelector,
                                                method_getImplementation(swizzledMethod),
                                                method_getTypeEncoding(swizzledMethod)),
                            method_getTypeEncoding(originalMethod));
    }
}

为什么交换实例方法的时候需要

class_replaceMethod(cls,
                            newSelector,
                            class_replaceMethod(cls,
                                                origSelector,
                                                method_getImplementation(swizzledMethod),
                                                method_getTypeEncoding(swizzledMethod)),
                            method_getTypeEncoding(originalMethod));

而交换类方法是只需要

method_exchangeImplementations(originalMethod, swizzledMethod);

看了许久,希望能得到帮助和理解

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.