특정 코드 method
가 호출 된 줄을 확인하는 방법이 있습니까?
특정 코드 method
가 호출 된 줄을 확인하는 방법이 있습니까?
답변:
이것이 도움이되기를 바랍니다.
NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
// Example: 1 UIKit 0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"];
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]];
[array removeObject:@""];
NSLog(@"Stack = %@", [array objectAtIndex:0]);
NSLog(@"Framework = %@", [array objectAtIndex:1]);
NSLog(@"Memory address = %@", [array objectAtIndex:2]);
NSLog(@"Class caller = %@", [array objectAtIndex:3]);
NSLog(@"Function caller = %@", [array objectAtIndex:4]);
완전히 최적화 된 코드에서는 특정 메서드에 대한 호출자를 결정하는 100 % 확실한 방법이 없습니다. 컴파일러는 마무리 호출 최적화를 사용할 수 있지만 컴파일러는 호출 수신자에 대해 호출자의 스택 프레임을 효과적으로 재사용합니다.
이에 대한 예를 보려면 gdb를 사용하여 주어진 메소드에 중단 점을 설정하고 역 추적을 살펴보십시오. 모든 메서드 호출 전에 objc_msgSend ()가 표시되지는 않습니다. 그 이유는 objc_msgSend ()가 각 메서드의 구현에 대한 마무리 호출을 수행하기 때문입니다.
최적화되지 않은 애플리케이션을 컴파일 할 수 있지만이 문제를 방지하려면 모든 시스템 라이브러리의 최적화되지 않은 버전이 필요합니다.
그리고 이것은 단지 하나의 문제 일뿐입니다. 실제로 "CrashTracer 또는 gdb를 어떻게 재창조합니까?"라고 묻는 것입니다. 경력을 쌓는 매우 어려운 문제입니다. "디버깅 도구"가 귀하의 경력이되기를 원하지 않는 한, 저는이 길을가는 것을 권장하지 않습니다.
정말로 대답하려고하는 질문은 무엇입니까?
intropedro가 제공 한 답변을 사용하여 다음 과 같이 생각해 냈습니다.
#define CALL_ORIGIN NSLog(@"Origin: [%@]", [[[[NSThread callStackSymbols] objectAtIndex:1] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"[]"]] objectAtIndex:1])
간단히 원래 클래스와 기능을 반환합니다.
2014-02-04 16:49:25.384 testApp[29042:70b] Origin: [LCallView addDataToMapView]
ps-performSelector를 사용하여 함수를 호출하면 결과는 다음과 같습니다.
Origin: [NSObject performSelector:withObject:]
이 작업을 수행하는 방법을 작성했습니다.
- (NSString *)getCallerStackSymbol {
NSString *callerStackSymbol = @"Could not track caller stack symbol";
NSArray *stackSymbols = [NSThread callStackSymbols];
if(stackSymbols.count >= 2) {
callerStackSymbol = [stackSymbols objectAtIndex:2];
if(callerStackSymbol) {
NSMutableArray *callerStackSymbolDetailsArr = [[NSMutableArray alloc] initWithArray:[callerStackSymbol componentsSeparatedByString:@" "]];
NSUInteger callerStackSymbolIndex = callerStackSymbolDetailsArr.count - 3;
if (callerStackSymbolDetailsArr.count > callerStackSymbolIndex && [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex]) {
callerStackSymbol = [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex];
callerStackSymbol = [callerStackSymbol stringByReplacingOccurrencesOfString:@"]" withString:@""];
}
}
}
return callerStackSymbol;
}
참조 용 @Intropedro의 답변의 Swift 2.0 버전;
let sourceString: String = NSThread.callStackSymbols()[1]
let separatorSet :NSCharacterSet = NSCharacterSet(charactersInString: " -[]+?.,")
let array = NSMutableArray(array: sourceString.componentsSeparatedByCharactersInSet(separatorSet))
array.removeObject("")
print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")
디버깅을 목적으로하는 경우에는 NSLog(@"%s", __FUNCTION__);
클래스의 각 메서드 내부의 첫 번째 줄로. 그러면 항상 디버거를보고 메서드 호출 순서를 알 수 있습니다.
@Roy Kronenfeld의 환상적인 답변의 약간 최적화 된 버전 :
- (NSString *)findCallerMethod
{
NSString *callerStackSymbol = nil;
NSArray<NSString *> *callStackSymbols = [NSThread callStackSymbols];
if (callStackSymbols.count >= 2)
{
callerStackSymbol = [callStackSymbols objectAtIndex:2];
if (callerStackSymbol)
{
// Stack: 2 TerribleApp 0x000000010e450b1e -[TALocalDataManager startUp] + 46
NSInteger idxDash = [callerStackSymbol rangeOfString:@"-" options:kNilOptions].location;
NSInteger idxPlus = [callerStackSymbol rangeOfString:@"+" options:NSBackwardsSearch].location;
if (idxDash != NSNotFound && idxPlus != NSNotFound)
{
NSRange range = NSMakeRange(idxDash, (idxPlus - idxDash - 1)); // -1 to remove the trailing space.
callerStackSymbol = [callerStackSymbol substringWithRange:range];
return callerStackSymbol;
}
}
}
return (callerStackSymbol) ?: @"Caller not found! :(";
}
안녕하세요.
//Add this private instance method to the class you want to trace from
-(void)trace
{
//Go back 2 frames to account for calling this helper method
//If not using a helper method use 1
NSArray* stack = [NSThread callStackSymbols];
if (stack.count > 2)
NSLog(@"Caller: %@", [stack objectAtIndex:2]);
}
//Add this line to the method you want to trace from
[self trace];
출력 창에 다음과 같은 내용이 표시됩니다.
발신자 : 2 MyApp 0x0004e8ae-[IINClassroomInit buildMenu] + 86
이 문자열을 구문 분석하여 스택 프레임에 대한 더 많은 데이터를 추출 할 수도 있습니다.
2 = Thread id
My App = Your app name
0x0004e8ae = Memory address of caller
-[IINClassroomInit buildMenu] = Class and method name of caller
+86 = Number of bytes from the entry point of the caller that your method was called
iOS의 식별 호출 방법에서 가져 왔습니다 .
@Geoff H의 Swift 4 버전 복사 및 붙여 넣기 ;]
let sourceString: String = Thread.callStackSymbols[1]
let separatorSet :CharacterSet = CharacterSet(charactersIn: " -[]+?.,")
var array = Array(sourceString.components(separatedBy: separatorSet))
array = array.filter { $0 != "" }
print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")
@Geoff H 답변의 Swift 3 버전은 다음과 같습니다.
let sourceString: String = Thread.callStackSymbols[1]
let separatorSet: CharacterSet = CharacterSet(charactersIn: " -[]+?.,")
let array = NSMutableArray(array: sourceString.components(separatedBy: separatorSet))
array.remove("")
print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")