มีวิธีการกำหนดบรรทัดของรหัสที่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 และดูที่ backtrace โปรดทราบว่าคุณไม่เห็น 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__);
เป็นบรรทัดแรกในแต่ละวิธีในชั้นเรียนของคุณ จากนั้นคุณสามารถทราบลำดับของการเรียกเมธอดได้ตลอดเวลาจากการดูที่ดีบักเกอร์
คุณสามารถส่งผ่านself
เป็นหนึ่งในอาร์กิวเมนต์ไปยังฟังก์ชันจากนั้นรับชื่อคลาสของวัตถุผู้โทรภายใน:
+(void)log:(NSString*)data from:(id)sender{
NSLog(@"[%@]: %@", NSStringFromClass([sender class]), data);
}
//...
-(void)myFunc{
[LoggerClassName log:@"myFunc called" from:self];
}
ด้วยวิธีนี้คุณสามารถส่งผ่านวัตถุใด ๆ ที่จะช่วยให้คุณทราบว่าปัญหาอาจเกิดขึ้นที่ใด
คำตอบที่ยอดเยี่ยมของ @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! :(";
}
@ennuikiller
//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])")