简体   繁体   English

performSelector可能导致泄漏,因为其选择器未知IN Singleton Class / FUNCTION Pointer -Passing Function作为参数

[英]performSelector may cause a leak because its selector is unknown IN Singleton Class/ FUNCTION Pointer -Passing Function as parameter

@interface URLClass : NSObject
{
    id target;
    SEL funObj;
}
+ (URLClass *)sharedInstance;
-(void)theBigFunction:(SEL)func :(id)target;
@property (nonatomic,retain) SEL funObj;

#import "URLClass.h"

static URLClass *instance = NULL;


@implementation URLClass
{
    NSMutableData *webData;
}
- (id)init
{
    if ( self = [super init] )
    {

    }
    return self;    
}

+ (URLClass *)sharedInstance
{
    @synchronized([URLClass class])
    {
        if (!instance)
            instance = [[super alloc] init];        
        return instance;
    }    
    return nil;
}
-(void)theBigFunction:(SEL)func :(id)targetObj{

    funObj =func;
    target=targetObj;  
    NSURL *URL = [NSURL URLWithString:@"urlString"];    
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];

    if( connection )
    {
        webData = [NSMutableData data] ;
    }
    else
    {
        NSLog(@"theConnection is NULL");
    }
}



-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{

    return YES;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{    
    NSLog(@"ERROR with theConenction");
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{    

    NSError *error;
    id jsonObj = [NSJSONSerialization JSONObjectWithData:webData options:0 error:&error];    
    if (jsonObj!=nil && error==nil) {        
        if ([jsonObj isKindOfClass:[NSDictionary class]]) {            
            NSDictionary *dic=(NSDictionary*)jsonObj;
            NSLog(@"DIC jsonObj %@ ",dic);
            NSArray *array=[dic objectForKey:@"items"];
            NSLog(@"array jsonObj %@  %d",array,[array count]);
        }else if ([jsonObj isKindOfClass:[NSArray class]]) {

            NSArray *arr=(NSArray*)jsonObj;
            NSLog(@"arr jsonObj %@ ",arr);
        }
    }
    [target performSelector:funObj];
// Not gEtting called the aboue line

//performSelector may cause a leak because its selector is unknown warning in above line } // performSelector可能会导致泄漏,因为它的选择器是上面行中的未知警告}

When am planing to execute below lines form code from any class . 当我计划执行下面的行形式来自任何类的代码。 its not get called. 它不被称为。

-(void)loginPress:(id)sender{
    URLClass *rlOBJ=[URLClass sharedInstance];   
    [rlOBJ theBigFunction:@selector(upd_Handler:) :self];
}
- (void) upd_Handler: (id) value{

    NSLog( @"Seccess");    
}

The modern approach would be for your class to accept a completion block instead of a target / selector. 现代方法是让您的类接受完成块而不是目标/选择器。 Then you don't have to insert a bunch of ugly compiler-inhibiting lines, and you get more flexibility. 然后你不必插入一堆丑陋的编译器抑制行,你就会获得更大的灵活性。

Here are complete replacements of [target performSelector:selector withObject:object]; 以下是[target performSelector:selector withObject:object];完全替换[target performSelector:selector withObject:object]; to avoid the warning. 避免警告。 Use either of the replacements like this: 使用这样的替换之一:

[NSObject target:target performSelector:selector withObject:object];

@interface NSObject (NSPerformSelector)

+ (id)target:(id)target performSelector:(SEL)selector;
+ (id)target:(id)target performSelector:(SEL)selector withObject:(id)object;
+ (id)target:(id)target performSelector:(SEL)selector withObject:(id)object1 withObject2:(id)object2;

@end

@implementation NSObject (NSPerformSelector)

+ (id)target:(id)target performSelector:(SEL)selector {

    IMP imp = [target methodForSelector:selector];
    id (*func)(id, SEL) = (void *)imp;
    return func(target, selector);
}

+ (id)target:(id)target performSelector:(SEL)selector withObject:(id)object {

    IMP imp = [target methodForSelector:selector];
    id (*func)(id, SEL, id) = (void *)imp;
    return func(target, selector, object);
}

+ (id)target:(id)target performSelector:(SEL)selector withObject:(id)object1 withObject2:(id)object2 {

    IMP imp = [target methodForSelector:selector];
    id (*func)(id, SEL, id, id) = (void *)imp;
    return func(target, selector, object1, object2);
}

@end

Simply use [sender performSelector:selector withObject:object afterDelay:0]; 只需使用[sender performSelector:selector withObject:object afterDelay:0]; This will remove the warning and the code will run fine. 这将删除警告,代码将运行正常。

That is a warning, not an error. 这是一个警告,而不是错误。 Your code should still work. 你的代码应该仍然有效。

When you invoke a selector and the compiler can't tell what the selector is, it can't tell if the called method is going to take ownership of the passed object or not, or release it, or whatever. 当您调用选择器并且编译器无法判断选择器是什么时,它无法判断被调用的方法是否将获取传递的对象的所有权,或者释放它,或者其他什么。 Thus ARC can't be sure that memory management of the parameter will be handled correctly. 因此ARC无法确定将正确处理参数的内存管理。

You should be able to enclosed the performSelector call in a compiler directive to disable that warning. 您应该能够在编译器指令中包含performSelector调用以禁用该警告。 Then the burden will be on you to make sure the called method does not keep any strong references to the object passed to it, or release the object. 然后,您将负担确保被调用的方法不会对传递给它的对象保持任何强引用,或释放该对象。

You don't need to pass your success method in your bigFunction. 您不需要在bigFunction中传递成功方法。 Instead you should be using a completion block, as suggested by [Wil Shipley][1] 相反,你应该使用完成块,如[Wil Shipley] [1]所建议的那样

Here is an example of a NSURLConnection making a Asynchronous request and returning; 以下是NSURLConnection发出异步请求并返回的示例; a response, data and an error; 响应,数据和错误; if one occurs. 如果有的话。 In the future you should refer to the documentation. 将来你应该参考文档。

NSURLConnection Class Reference https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/index.html NSURLConnection类参考https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/index.html

+ (void)sendAsynchronousRequest:(NSURLRequest *)request
                      queue:(NSOperationQueue *)queue
          completionHandler:(void (^)(NSURLResponse *response,
                                      NSData *data,
                                      NSError *connectionError))handler

You could re-write your bigFunction method like this -- 你可以像这样重写你的bigFunction方法 -

- (void)bigFunctionWithYourInputData:(NSDictionary*)userInfo withCompletionHandler:(void(^)(NSData* data, NSError* error))completionHandler {
    NSURL *theUrl = [NSURL URLWithString:[userInfo objectForKey:@"url"];
    NSURLRequest *req = [NSURLRequest requestWithURL:theUrl];
   [NSURLConnection sendAsynchronousRequest:req queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        if (!connectionError) {
            //do what you want with your data
            NSLog(@"response :%@", response);
            NSLog(@"data     :%@", data);

            //pass to your completion handler
            if(completionHandler) {
                completionHandler(data, nil);
            }
        } else {
            //something went wrong
            NSLog(@"Got the error with code :%ld", (long)connectionError.code);

            //pass to your completion handler
            if(completionHandler) {
                completionHandler(nil, error);
            }
        }
    }];
}

Then you would implement it somewhere else, via your singleton like so -- 然后你会通过你的单身人士在其他地方实现它 -

[URLClass sharedInstance] bigFunctionWithYourInputData:_someDictionaryData withCompletionHandler:^(NSData* data, NSError* error) {

     if (!error) {
         //success
         NSLog(@"returned the data:%@", data);

     } else {

         //handler the error somehow
     }
 }];  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 performSelector 可能会导致泄漏,因为它的选择器是未知的 - performSelector may cause a leak because its selector is unknown Apple Demo没有“ performSelector可能会导致泄漏,因为其选择器未知”警告。 有人知道为什么吗? - Apple Demo don't have “performSelector may cause a leak because its selector is unknown” Warning. Anyone know why? 执行选择器可能会导致泄漏,因为选择未知? - Perform selector may cause leak because select is unknown? PerformSelector可能会导致泄漏-更好的解决方案 - PerformSelector may cause a leak - Better solution 将 swift 中的闭包作为参数传递给 function 中的选择器使用 - Passing closure in swift as parameter to be used by selector in function 类参数为可选函数指针,无法识别为函数 - Class parameter as optional function pointer not recognised as function 全局函数和AppDelegate类的performSelector错误 - performSelector error with global function and AppDelegate class 使用选择器参数从 swift 到 objc 的 performSelector 不起作用 - performSelector from swift to objc with selector parameter not work [project] 的 Xcode 功能警告可能无法正常运行,因为其权利使用占位符团队 ID - Warning for Xcode Capabilities for [project] may not function correctly because its entitlements use a placeholder team ID 选择器和PerformSelector - selector and PerformSelector
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM