วิธีการตั้งค่าเบรกพอยต์แบบมีเงื่อนไขใน Xcode ตามคุณสมบัติสตริงอ็อบเจ็กต์


93

ฉันต้องการให้ตัวดีบั๊กหยุดพักเมื่อถึงการจับคู่สตริงที่เฉพาะเจาะจง ตัวอย่างเช่นฉันอาจมีสิ่งนี้:

Foo myObj = [self gimmeObj];

myObjnameอาจมีคุณสมบัติที่เรียกว่า ฉันต้องการให้ดีบักเกอร์หยุดงานเมื่อ

[myObj.name isEqualToString:@"Bar"];

ฉันจะตั้งค่าเบรกพอยต์ตามเงื่อนไขใน Xcode ให้ทำเช่นนั้นได้อย่างไร

คำตอบ:


184

คุณสามารถตั้งค่าจุดพักตามเงื่อนไขใน Xcode ได้โดยการตั้งค่าเบรกพอยต์ตามปกติจากนั้นกด Control แล้วคลิกและเลือกแก้ไขเบรกพอยต์ (เลือกรัน -> แสดง -> เบรกพอยต์)

ในรายการเบรกพอยต์มีคอลัมน์เงื่อนไข

ตอนนี้มีหลายประเด็นที่ต้องคำนึงถึงสภาพ ประการแรก gdb ไม่เข้าใจไวยากรณ์ dot ดังนั้นแทนที่จะใช้ myObj.name คุณต้องใช้ [myObj name] (เว้นแต่ชื่อจะเป็น ivar)

ถัดไปเช่นเดียวกับนิพจน์ส่วนใหญ่ใน gdb คุณต้องระบุประเภทของผลลัพธ์ที่ส่งคืนคือ "BOOL" ดังนั้นตั้งเงื่อนไขเช่น:

(BOOL)[[myObj name] isEqualToString:@"Bar"]

บ่อยครั้งที่มันง่ายกว่าที่จะทำในโค้ดโดยการเพิ่มโค้ดชั่วคราวเช่น:

if ( [myObj.name isEqualToString:@"Bar"] ) {
    NSLog( @"here" );
}

จากนั้นตั้งค่าจุดพักบน NSLog จากนั้นเงื่อนไขของคุณอาจซับซ้อนโดยพลการโดยไม่ต้องกังวลว่า gdb สามารถและแยกวิเคราะห์ไม่ได้


12
ยกเว้นว่าคุณจะเสี่ยงต่อการลืมลบการบันทึกหรือเปลี่ยนแปลงพฤติกรรมของคุณ
Pål Brattberg

3
นั่นคือเรื่องจริง ฉันมักจะลดปัญหานี้โดยการเพิ่ม "NYI" (ยังไม่ได้ดำเนินการ) ลงในสตริงจากนั้นการค้นหาตรวจสอบก่อนวางจำหน่ายสำหรับ NYI ของฉันจะตรวจจับ
Peter N Lewis

18
เพื่อให้ได้ผลนี้ฉันต้องสร้าง (บูล) ตัวพิมพ์ใหญ่เป็น (BOOL) อาจเป็นสิ่งที่ LLDB
Wex

1
บูลไม่ทำงานสำหรับฉันใน GDB ผมต้องใช้ BOOL หรือ int- ความแตกต่างจะมีการอธิบายที่นี่stackoverflow.com/a/544250/725871
Chaosphere2112

2
คุณไม่สามารถใส่รหัสได้หากคุณมีบั๊กของเกมทุกๆ 200 ครั้งซึ่งในที่สุดก็เกิดขึ้นและตอนนี้คุณต้องทำเบรกพอยต์แบบมีเงื่อนไข การหยุดโปรแกรมเพื่อแก้ไขโค้ดไม่ใช่ทางเลือก
Almo

21

นี่คือวิธีการใช้เบรกพอยต์ตามเงื่อนไข XCode lldb

ขั้นแรกให้ดับเบิลคลิกที่จุดพัก (หรือคลิกขวาedit breakpoint) คุณจะเห็นป๊อปอัปโต้ตอบ

ป้อนคำอธิบายภาพที่นี่

นี่คือความหมายของตัวเลือกเหล่านั้น:

  1. เงื่อนไข : เบรกพอยต์จะยิงภายใต้เงื่อนไขนี้เท่านั้น
  2. ละเว้น : จำนวนครั้งที่เงื่อนไขต้องเป็นไปตามก่อนที่จะยิงเบรกพอยต์
  3. การดำเนินการ : การดำเนินการที่ทำงานหลังจากเบรกพอยต์แตก
  4. ตัวเลือก : ดำเนินการต่อโดยอัตโนมัติหลังจากประเมินการกระทำ

นี่คือบทสรุป สำหรับตัวอย่างด้านบนในภาพหมายความว่าเมื่อตัวแปรbuildingIdเท่ากับ 13 ให้แบ่งตรงนี้ ถ้าฉันเพิ่มเวลาละเว้นเป็น 1 เวลาจะไม่สนใจครั้งแรกเมื่อbuildingIdเท่ากับ 13 และแตกในครั้งที่สองตามเงื่อนไข

สำหรับการดำเนินการเมื่อคุณกด add actions จะมีรายการให้เลือก โดยปกติสิ่งที่ฉันทำคือใช้Debugger Command poเพื่อพิมพ์ตัวแปรที่ฉันต้องตรวจสอบและฉันเชื่อว่ามีวิธีที่ดีกว่าในการใช้การกระทำแล้วฉันก็ทำ

ดูเหมือนว่าคุณต้องคอมไพล์ใหม่และเรียกใช้แอพหากคุณเปลี่ยนเงื่อนไขในรันไทม์


อาจเป็นเพราะคำถามเกี่ยวกับการหยุดที่เบรกพอยต์ตามค่าสตริง [ฉันไม่ใช่ผู้ลงคะแนน]
ZS

1
ขอบคุณมีประโยชน์มาก คำตอบนี้สมควรได้รับการโหวตมากขึ้น
andreskwan

7

ฉันไม่แน่ใจว่าจะได้ผลหรือไม่ แต่คุณสามารถลองตั้งค่าเบรกพอยต์ที่บรรทัดของโค้ดนั้นเปิดคอนโซลดีบักเกอร์ (Cmd + Shift + R) แล้วพิมพ์

condition N (int)[[myObj name] isEqualToString:@"Bar"]

โดยที่ N ถูกแทนที่ด้วยจำนวนของเบรกพอยต์ (จำนวนเต็ม)


2

หากคุณกลายพันธุ์ myObj.name โดยใช้ตัวตั้งค่าคุณสามารถเพิ่มเบรกพอยต์เชิงสัญลักษณ์-[MyObjClass setName:]จากคอนโซลดีบักเกอร์หรือจากเมนู Run-> Manage Breakpoints-> Add Symbolic Breakpoint ใน Xcode ถ้าไม่ (เพราะเหตุใดคุณอาจไม่ควรแก้ไขตัวแปรอินสแตนซ์โดยตรงยกเว้นใน initializer หรือ dealloc ที่กำหนด) คุณสามารถตั้งค่า watchpoint ใน gdb (ใช้ Debugger Console ใน Xcode เมื่อดีบักเกอร์ทำงาน) หน้านี้จะอธิบายวิธีการ ฉันไม่เชื่อว่า Xcode เปิดเผย UI สำหรับการตั้งค่า watchpoints โดยไม่ใช้ Debugger Console


0

ในบางครั้งเมื่อทำงานกับ Frameworks (debug builds) และจำเป็นต้องวางเบรกพอยต์ในไฟล์ / ตำแหน่งบางอย่างที่ยากต่อการนำทางหรือไม่เปิดเผยต่อสาธารณะในเฟรมเวิร์กที่กำลังพัฒนา ทางเลือกหนึ่งคือการเขียนคลาสตัวช่วยเพื่อทริกเกอร์เบรกพอยต์แบบมีเงื่อนไขและทำให้ขั้นตอนเข้า / ออกได้ง่ายขึ้น

- (void)invokeFrameworkMethod {
    ...
    [DebugConditionalBreakPointHelper breakPointCondition:YES comment:@"from invokeFrameworkMethod."];
    ...
}

การประกาศส่วนหัวในกรอบภายใต้การพัฒนา

#import <Foundation/Foundation.h>

@interface DebugConditionalBreakPointHelper : NSObject
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment;
@end

และไฟล์การนำไปใช้งาน:

#import "DebugConditionalBreakPointHelper.h"

@implementation DebugConditionalBreakPointHelper
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment {
    if (enabled)
    {
        NSLog(@"Triggerred Conditional Break Point. Comment: %@");
    }
}
@end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.