ประเด็นของ NSAssert คืออะไร


155

ฉันต้องถามสิ่งนี้เพราะ: สิ่งเดียวที่ฉันจำได้คือว่าหากการยืนยันล้มเหลวแอปก็จะขัดข้อง นั่นคือเหตุผลที่จะใช้ NSAssert หรือไม่ หรือประโยชน์อื่นของมันคืออะไร? และมันถูกต้องหรือไม่ที่จะวาง NSAssert ให้อยู่เหนือข้อสันนิษฐานใด ๆ ที่ฉันทำในโค้ดเช่นฟังก์ชันที่ไม่ควรรับ -1 เป็นพารามิเตอร์ แต่อาจเป็น -0.9 หรือ -1.1?

คำตอบ:


300

ยืนยันคือเพื่อให้แน่ใจว่าค่าเป็นสิ่งที่ควรจะเป็น หากการยืนยันล้มเหลวนั่นหมายความว่ามีบางอย่างผิดปกติดังนั้นแอปจะหยุดทำงาน เหตุผลหนึ่งในการใช้ assert คือหากคุณมีฟังก์ชั่นบางอย่างที่จะไม่ทำงานหรือจะสร้างผลข้างเคียงที่เลวร้ายมากหากพารามิเตอร์ตัวใดตัวหนึ่งที่ส่งผ่านไปนั้นไม่ใช่ค่าบางอย่าง (หรือช่วงของค่า) คุณสามารถใส่ assert ตรวจสอบให้แน่ใจว่าค่านั้นเป็นสิ่งที่คุณคาดหวังว่าจะเป็นและถ้าไม่ใช่ก็มีบางอย่างผิดปกติจริง ๆ ดังนั้นแอปจะหยุดทำงาน การยืนยันสามารถเป็นประโยชน์อย่างมากสำหรับการดีบัก / ทดสอบหน่วยและเมื่อคุณจัดเตรียมเฟรมเวิร์กเพื่อหยุดผู้ใช้ไม่ให้ทำสิ่งที่ "ชั่วร้าย"


9
คุณควรนำ NSAssert ออกเพื่อรับการปล่อยตัว มีการรวบรวมเวลาทำเช่นนั้น
Barry Wark

127
> คุณควรนำ NSAssert ออกเพื่อรับการปล่อยตัว นี่เป็นปัญหาที่ถกเถียงกัน ฉันมักจะปล่อยแอปพลิเคชันของฉันด้วยการเปิดใช้งานการยืนยันและนี่เป็นวิธีปฏิบัติมาตรฐานสำหรับซอฟต์แวร์จำนวนมากเช่น Apple ทำสิ่งนี้ ทันทีที่โปรแกรมของคุณตรวจพบสถานะผิดปกติคุณควรผิดพลาด คุณสามารถรับการติดตามสแต็คว่ามีข้อผิดพลาดเกิดขึ้นที่ใดในขณะที่ถ้าคุณปิดการใช้งาน asserts คุณอาจท้ายหน่วยความจำที่เสียหายและ / หรือข้อมูลผู้ใช้และปัญหาจะยากต่อการดีบัก
Mike Weller

18
โปรดทราบว่า XCode 4 มี NS_BLOCK_ASSERTIONS ที่กำหนดโดยค่าเริ่มต้นในการกำหนดค่าการเปิดตัว ฉันเดาว่าถ้าคุณไม่เปลี่ยนรหัสที่ออกมาของคุณจะไม่มี NSAssert: s
จอนนี่

16
หากฉันเข้าใจอย่างถูกต้องจุดที่ควรทิ้งไว้คืออะไร (ในเวอร์ชั่นที่วางจำหน่าย) ทำไมไม่เปลี่ยน NSAssert ด้วยคำสั่ง if และถ้า (มีบางสิ่งที่น่ากลัวเกิดขึ้น) ให้แจ้งผู้ใช้ (หรือทำสิ่งที่อยู่ภายใต้การควบคุมของคุณ ) และไม่ใช่แค่เลิก / หยุดทำงานและปล่อยให้ผู้ใช้สงสัยว่าเกิดอะไรขึ้น ... หรือ ฉันพลาดอะไรไปรึเปล่า?
Gik

11
มันเป็นการเสียเวลานักพัฒนาที่จะลงไปสู่เส้นทางของทุกกรณีพิเศษที่ไม่ควรเกิดขึ้นภายใต้สถานการณ์ปกติ วิธีนี้เกี่ยวข้องกับการคิดหาวิธีที่เหมาะสมในการแจ้งผู้ใช้สำหรับแต่ละคนและ / หรือทำให้แอปมีความแข็งแกร่งเพียงพอที่จะดำเนินการในลักษณะที่คาดหวังหลังจากเกิดขึ้น วิธีปฏิบัติที่เป็นไปได้มากขึ้นคือทำให้แอปผิดพลาดและแก้ไขข้อบกพร่องที่พบในรายงานข้อขัดข้องและปล่อยเวอร์ชันใหม่ ต้องบอกว่ามันเป็นสิ่งสำคัญเพื่อให้แน่ใจว่าไม่มีการสูญหายของข้อมูลในสถานการณ์เช่นนี้ นี้จะต้องได้รับการรับรอง แต่มันเป็นงานที่ไกลน้อยกว่า
trss

20

ฉันไม่สามารถพูดกับ NSAssert ได้จริง ๆ แต่ฉันจินตนาการว่ามันทำงานคล้ายกับการยืนยันของ C ()

assert () ใช้ในการบังคับใช้สัญญาความหมายในรหัสของคุณ คุณถามว่าอะไร

มันก็เหมือนกับที่คุณพูดว่า: ถ้าคุณมีฟังก์ชั่นที่ไม่ควรได้รับ -1 คุณสามารถยืนยัน () บังคับใช้:

โมฆะ gimme_positive_ints (int i) {
  ยืนยัน (i> 0);
}

และตอนนี้คุณจะเห็นสิ่งนี้ในบันทึกข้อผิดพลาด (หรือ STDERR):

การยืนยัน i> 0 ล้มเหลว: ไฟล์ example.c, บรรทัด 2

ดังนั้นไม่เพียงป้องกันความปลอดภัยที่อาจเกิดจากอินพุตที่ไม่ดีเท่านั้น แต่ยังบันทึกข้อมูลเหล่านั้นด้วยวิธีมาตรฐานที่เป็นประโยชน์

โอ้และอย่างน้อยก็ใน C assert () เป็นมาโครดังนั้นคุณสามารถกำหนด assert () ใหม่เป็นแบบไม่ใช้ในโค้ดการเปิดตัวของคุณ ฉันไม่ทราบว่าเป็นกรณีของ NSAssert (หรือแม้กระทั่งยืนยัน () อีกต่อไป) แต่มันมีประโยชน์มากที่จะรวบรวมเช็คเหล่านั้น


2
ใช่ NSAssert เป็นมาโครเช่นกัน
Martin Wickman

18

NSAssertให้คุณมากกว่าแค่แอพที่ล้มเหลว มันบอกคุณชั้นเรียนวิธีการและบรรทัดที่มีการยืนยันเกิดขึ้น การยืนยันทั้งหมดสามารถปิดใช้งานได้อย่างง่ายดายโดยใช้ NS_BLOCK_ASSERTIONS ดังนั้นจึงเหมาะสำหรับการแก้ไขข้อบกพร่อง ในทางกลับกันการขว้างNSExceptionเพียงแอปขัดข้อง นอกจากนี้ยังไม่ได้บอกตำแหน่งของข้อยกเว้นและไม่สามารถปิดใช้งานได้อย่างง่ายดาย ดูความแตกต่างในภาพด้านล่าง

แอปขัดข้องเนื่องจากการยืนยันยังทำให้เกิดข้อยกเว้นเนื่องจากเอกสารคู่มือ NSAssert :

เมื่อเรียกใช้ตัวจัดการการยืนยันจะพิมพ์ข้อความแสดงข้อผิดพลาดที่มีเมธอดและชื่อคลาส (หรือชื่อฟังก์ชัน) จากนั้นเพิ่มข้อยกเว้น NSInternalInconsistencyException

NSAssert:

บันทึกหลังจากยืนยัน

NSException:

บันทึกหลังจากข้อยกเว้น


NSExceptionให้ความอุดมสมบูรณ์ของโอกาสที่จะกำหนดผลลัพธ์มันกลับผ่านreasonและuserInfoพารามิเตอร์ ไม่มีเหตุผลที่คุณไม่สามารถเพิ่มชื่อคลาสตัวเลือกข้อมูลบรรทัดและสิ่งอื่นใดที่คุณต้องการเพิ่มเพื่อช่วยในการดีบัก IMHO คุณใช้NSAssertสำหรับการดีบักในระหว่างการพัฒนา แต่ปิดการใช้งานเพื่อจัดส่ง คุณโยนNSExceptionถ้าคุณต้องการที่จะออกในการยืนยันในรหัสการจัดส่งสินค้า
markeissler

17

นอกเหนือจากที่ทุกคนกล่าวไว้ข้างต้นพฤติกรรมเริ่มต้นของNSAssert()(ซึ่งแตกต่างจากของ C assert()) คือการโยนข้อยกเว้นซึ่งคุณสามารถจับและจัดการ ตัวอย่างเช่น Xcode ทำสิ่งนี้


มีมากขึ้นเกี่ยวกับวิธีที่เราสามารถจับและจัดการข้อยกเว้นได้หรือไม่?
Gon

1
ข้อยกเว้นในโกโก้ไม่ใช่พฤตินัย "ที่จับได้และจับได้" หากการควบคุมผ่านแอปเปิ้ลฟังก์ชั่นทุกที่ในสายการโทรพฤติกรรมจะไม่ได้กำหนด ข้อยกเว้นนั้นมีไว้สำหรับการรายงานข้อผิดพลาด (aka crittercism ฯลฯ ) เท่านั้นไม่ใช่เพื่อการใช้งานทั่วไปเช่นใน Java
Michael

9

เพื่ออธิบายอย่างที่ใครบางคนพูดถึง แต่ไม่ได้อธิบายอย่างสมบูรณ์เหตุผลในการมีและใช้ asserts แทนที่จะสร้างรหัสที่กำหนดเอง (เช่นการทำ ifs และเพิ่มข้อยกเว้นสำหรับข้อมูลที่ไม่ดีเป็นต้น) นั่นคือ asserts SHOULD ถูกปิดใช้งาน

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

จากความช่วยเหลือของ NSAssert: "การยืนยันถูกปิดใช้งานหากมีการกำหนดแมโครมาก่อนตัวประมวลผล NS_BLOCK_ASSERTIONS" ดังนั้นเพียงแค่ใส่มาโครในเป้าหมายการแจกจ่ายของคุณ [เท่านั้น]


6

NSAssert(และ stdlib ที่เทียบเท่าassert) เพื่อตรวจหาข้อผิดพลาดในการเขียนโปรแกรมในระหว่างการพัฒนา คุณไม่ควรมีคำยืนยันที่ล้มเหลวในแอปพลิเคชั่นที่ผลิต (ปล่อยตัว) ดังนั้นคุณอาจยืนยันว่าคุณไม่เคยส่งจำนวนลบไปยังวิธีการที่ต้องมีอาร์กิวเมนต์เป็นบวก หากการยืนยันล้มเหลวระหว่างการทดสอบคุณมีข้อบกพร่อง อย่างไรก็ตามหากค่าที่ส่งผ่านนั้นถูกป้อนโดยผู้ใช้คุณจำเป็นต้องทำการตรวจสอบความถูกต้องของอินพุตแทนการใช้การยืนยันในการผลิต (คุณสามารถตั้งค่า #define สำหรับรุ่นบิลด์ที่ปิดใช้งานNSAssert*ได้


2
+1 เพราะคำตอบของคุณเหมาะสมกับฉันมากที่สุด! การใช้ NSAssert เหมาะสมกว่าหากใช้เพื่อการพัฒนาไม่ใช่หลังจากออกวางจำหน่าย ผู้ใช้ที่ป้อนค่าที่ไม่ได้รับอนุญาตควรตามด้วยข้อผิดพลาด UI ไม่ใช่ NSAssert หยุดแอปพลิเคชัน หมอกจางลง!
pnizzle

3

โดยทั่วไปมักใช้การยืนยันเพื่อบังคับให้ใช้วิธีการเฉพาะหรือชิ้นส่วนของตรรกะ สมมติว่าคุณกำลังเขียนวิธีที่คำนวณผลรวมของสองจำนวนเต็มมากกว่าศูนย์ เพื่อให้แน่ใจว่ามีการใช้วิธีการตามที่ตั้งใจไว้เสมอคุณอาจจะต้องทำการยืนยันซึ่งเป็นการทดสอบสภาพนั้น

คำตอบสั้น ๆ : พวกเขาบังคับให้ใช้รหัสของคุณตามที่ตั้งใจไว้เท่านั้น


3

มันคุ้มค่าที่จะชี้ให้เห็นว่านอกเหนือจากการตรวจสอบเวลาทำงานการเขียนโปรแกรมยืนยันเป็นสิ่งสำคัญที่ใช้เมื่อคุณออกแบบรหัสของคุณตามสัญญา

ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องของการยืนยันและการออกแบบโดยสัญญาสามารถดูได้ที่ด้านล่าง:

การยืนยัน (การพัฒนาซอฟต์แวร์)

ออกแบบตามสัญญา

การเขียนโปรแกรมด้วยการยืนยัน

ออกแบบโดยสัญญาตามตัวอย่าง [ปกอ่อน]


2

เพื่อตอบคำถามของเขาอย่างเต็มที่จุดประสงค์ของการยืนยันประเภทใดก็เพื่อช่วยในการดีบั๊ก การจับข้อผิดพลาดจากแหล่งที่มานั้นมีประโยชน์มากขึ้นจากนั้นจึงจับพวกเขาในตัวดีบักเมื่อเกิดข้อผิดพลาด

ตัวอย่างเช่นคุณอาจส่งผ่านค่าไปยังฟังก์ชันที่คาดหวังค่าในช่วงที่กำหนด ฟังก์ชันนี้อาจเก็บค่าไว้เพื่อใช้ในภายหลังและในภายหลังจะใช้แอปพลิเคชันขัดข้อง สแตกการโทรที่เห็นในสถานการณ์นี้จะไม่แสดงแหล่งที่มาของค่าที่ไม่ถูกต้อง มันเป็นการดีกว่าที่จะจับค่าที่ไม่ดีเมื่อพบว่าใครกำลังผ่านค่าที่ไม่ดีและเพราะเหตุใด


-3

NSAssertทำให้แอปหยุดทำงานเมื่อตรงกับเงื่อนไข หากไม่ตรงกับเงื่อนไขข้อความถัดไปจะทำงาน มองหา EX ด้านล่าง:

ฉันเพิ่งสร้างแอพเพื่อทดสอบว่างานNSAssertคืออะไร:

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testingFunction:2];
}

-(void)testingFunction: (int)anNum{
    // if anNum < 2 -> the app will crash
    // and the NSLog statement will not execute
    // that mean you cannot see the string: "This statement will execute when anNum < 2"
    // into the log console window of Xcode
    NSAssert(anNum >= 2, @"number you enter less than 2");
    // If anNum >= 2 -> the app will not crash and the below 
    // statement will execute
    NSLog(@"This statement will execute when anNum < 2");
}

ในรหัสของฉันแอพจะไม่พังและกรณีทดสอบคือ:

  • anNum > = 2 -> แอพจะไม่ทำงานผิดพลาดและคุณสามารถเห็นสตริงการบันทึก: "คำสั่งนี้จะทำงานเมื่อ anNum <2" ในหน้าต่างคอนโซลบันทึก outPut
  • anNum <2 -> แอพจะทำงานล้มเหลวและคุณไม่เห็นสตริงบันทึก: "คำสั่งนี้จะทำงานเมื่อมีจำนวน <2"

1
คุณได้รับมันในทางตรงกันข้าม "NSAssert ทำให้แอปขัดข้องเมื่อตรงกับเงื่อนไขหากไม่ตรงกับเงื่อนไขข้อความถัดไปจะทำงาน" NSAssert ขัดข้องแอปหากไม่ตรงกับเงื่อนไขและดำเนินการตามปกติหากตรงกับเงื่อนไข
Joe Tam

แอปขัดข้องและบันทึกข้อความเมื่อไม่เป็นไปตามเงื่อนไข
Pravin S.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.