2013-04-18 18 views
7

NSInvocation 's -retainArguments yöntemi, NSInvocation'u hemen çalıştırdığınız zaman için yararlıdır, ancak daha sonra gerçekleştirin; Bu süre boyunca geçerli kalmaları için nesne argümanlarını korur.- [NSInvocation retainArguments] kopyalarını engeller mi?

Hepimizin bildiği gibi, blok argümanları saklanmak yerine kopyalanmalıdır. Benim sorum şu, blok türü ne zaman bir argüman tutmak yerine -retainArguments kopyalamak biliyor mu? Dokümantasyon bunu yaptığını göstermez, ancak yapılması kolay ve mantıklı bir şey gibi görünüyor.

Güncelleme: davranış sadece bu test ile iOS 6.1 ve -retainArguments, önce blok tipi parametrelerini kopyalamak vermedi iOS 7'de değişmiş gibi görünüyor. IOS 7 ve daha sonra, -retainArguments, blok türünün parametrelerini kopyalamaz. -retainArguments dokümantasyonunun blokları kopyaladığını, ancak davranış değiştiğinde (eski işletim sistemlerini destekleyen kişiler için gerçekten tehlikeli olan) olmadığını söylemiştir. Cevap NSInvocation blok kopyalamak için yeterince akıllı olduğu, evetse

+0

Bu güncelleştirmeyi sakladığınız için teşekkür ederiz! – matt

cevap

1

sayılı

Görüntü, böyle bir şey yapmak gerekir:

for (/*every arguments*/) { 
    if (/*arg is object. i.e. @encode(arg) is '@'*/) { 
     if ([arg isKindOfClss:[NSBlock class]]) { 
      arg = [arg copy]; // copy block 
     } else { 
      [arg retain]; 
     } 
    } 
} 

sorun kopyalanırken arg değiştirilmiş olmasıdır Bu, retainArguments numaralı aramanın NSInvocation'daki argümanları değiştirebileceği anlamına gelmeyecek olan blok. , bu zaten yapılmış olan birçok varsayımı bozacaktır.


Güncelleme (argümanlar NSInvocation oluşturmak için kullanıldığı gibi yani argümanlar aynı olmalıdır NSInvocation aldığım)

cevap uymak testi HAYIR, ama benim önceki noktasıydı tıpkı yanlış olsa ...

@interface Test : NSObject 

@end 

@implementation Test 

- (void)testMethodWithBlock:(void (^)(void))block obj:(id)obj cstr:(const char *)cstr { 
    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 
} 

@end 

@implementation testTests 

- (void)test1 { 
    __block int dummy; 
    Test *t = [[Test alloc] init]; 
    NSMethodSignature *ms = [t methodSignatureForSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:ms]; 
    void (^block)(void) =^{ 
     dummy++; // stop this become global block 
    }; 
    id obj = @"object"; 
    char *cstr = malloc(5); 
    strcpy(cstr, "cstr"); 


    NSLog(@"%@", [ms debugDescription]); 

    NSLog(@"%p %p %p %@", block, obj, cstr, [block class]); 

    [invocation setSelector:@selector(testMethodWithBlock:obj:cstr:)]; 
    [invocation setArgument:&block atIndex:2]; 
    [invocation setArgument:&obj atIndex:3]; 
    [invocation setArgument:&cstr atIndex:4]; 

    [invocation invokeWithTarget:t]; 

    [invocation retainArguments]; 

    [invocation invokeWithTarget:t]; 

    free(cstr); 
} 

@end 

çıkışı, ARC devre dışı (ve çöktü):

2013-04-18 19:49:27.616 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.617 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__ 
2013-04-18 19:49:27.618 test[94555:c07] 0xbfffe120 0x70d2254 0x736a810 __NSStackBlock__ 

ARC etkin:

2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__ 
2013-04-18 19:51:03.980 test[95323:c07] 0x7101e10 0x70d2268 0xe0c1310 __NSMallocBlock__ 

gördüğünüz gibi, c dize retainArguments ancak blokların tarafından kopyalanır. ama ARC etkinken, sorun bir noktada ARC'nin sizin için kopyaladığı için sorun gitmelidir.

+0

Bir bloğun kopyalanması, sistem tipinin neyle ilgilendiğini değiştirmez, bloğun imzası. Elbette, bir __NSStackBlock__'dan bir '__NSHeapBlock__' öğesine gidebilir, ancak bu bir bloğu kopyalamanın noktasıdır: ömrünü uzatmak için yığına taşımaktır. – CodaFi

+0

İyi nokta. Ancak, -retainArguments de C dizelerini kopyalar. Ve C dizelerini kopyalamak da argümanları değiştirir. – user102008

+0

@CodaFi benim noktanız 'blok! = [Blok kopya]' bu yüzden –

4

Bu kesinlikle (her ne kadar kendim test etsem de). documentation göre:

retainArguments

alıcı Önceden yapmadıysanız ise, hedef ve alıcı ve kopya onun C-string argümanları ve blokların hepsi bütün nesne argümanları korur.

  • (boşluk) retainArguments

bu yöntem çağrılır önce Tartışma

NO döner argumentsRetained; sonra, YES döner.

verimlilik için, yeni oluşturulan NSInvocation nesneleri korumaz veya C dizeleri savlarını kopyalamak, ne de onların hedefini korumak yapmak, kopyalamak veya herhangi ilişkili blokları kopyalayın. NSInvocation nesnesini, önbelleği çağrılırsa argümanlarını saklamak için yönlendirmeniz gerekir; çünkü argümanlar çağrılmadan önce aksi halde serbest bırakılabilir. NSTimer nesneleri her zaman çağrılarını, zamanlayıcı yangınlardan önce gecikmesi olduğu için argümanlarını koruyarak numaralarına bildirir.

+0

İlginç alanının ötesine uzatıldı. Belgeler değişti: https://web.archive.org/web/20120826185131/http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html # // apple_ref/occ/instm/NSInvocation/retainArguments Ama davranış değiştiğinde ve ne zaman değiştiğini belgelemez. Bir yıl önce iOS 6'da denediğimde, bloklar kesinlikle "retainArguments" tarafından kopyalanmadı. – user102008

+1

Sadece test ettim ve iOS 7'de değil iOS 6.1'de kopyalandı, böylece değişti. – user102008

+0

Değişiklik, ios 7 güncellemesi olarak belgelenmiş olmalıydı, aksine her zaman olduğu gibi görünüyordu ... aptal Elma, püf noktaları çocuklar için! –