อาจพูดได้ว่าไม่มี Objective-C programmer คนไหนเลยไม่เคยเจอปัญหา EXC_BAD_ACCESS และปัญหานี้ก็มักตามมากวนใจอยู่เนืองๆ จนบางทีอาจทำให้เราต้องเสียเวลาหาต้นเหตุของปัญหานี้เป็นเวลานานจนน่าหงุดหงิด
เริ่มจากทดลองสร้างโปรแกรมที่ทำให้เกิดปัญหานี้ก่อน โดยเราจะสร้าง 2 method ขึ้นมาดังนี้
และ
กำหนดให้สองเหตุการณ์นี้ทำงานต่อเนื่องกัน เหตุการณ์ละรอบ
เหตุการณ์แรก เมื่อ method setString ทำงานจะสร้าง object ของ NSArray และเก็บไว้ใน instance variable ชื่อ _myArray
เหตุการณ์ที่สอง เมื่อ method getString ทำงาน จะทำการอ่านค่่าจาก _myArray ออกมาแสดง
เมื่อเราสั่งให้โปรแกรมทำงานจะพบ EXC_BAD_ACCESS ออกมาทาง debugger ดังนี้
เหตุผลก็เพราะว่า object ที่ได้จาก method setString จะเป็น autorelease object ดังนั้นแน่นอนว่ามันจะถูกส่งเข้าไปอยู่ใน autorelease pool และถูก release ทิ้งไปเมื่อจบรอบแรกโดยอัตโนมัติ ซึ่งเหตุการณ์จริงอาจไม่ได้หาต้นเหตุของปัญหาง่ายแบบนี้ก็ได้
วิธีตามหาต้นตอของ EXC_BAD_ACCESS เราจะกำหนด parameter ให้กับ Executables ที่อยู่ด้านซ้ายของ xcode window ให้ double click และเลือก get info และไปที่ tab Arguments จากนั้นเพิ่ม NSZombieEnabled และกำหนดค่าเป็น YES เข้าไปดังนี้
NSZombieEnabled เป็น parameter ที่ช่วยบอกว่ามี message ไหนส่งไปหา object ที่ถูก deallocate แล้ว
จากนั้นลองรันโปรกรมเดิมใหม่แทนที่จะโดนตอบกลับมาด้วย EXC_BAD_ACCESS (ซึ่งไม่ช่วย hint อะไรเท่าไหร่นัก) อีก ก็จะได้ผลออกมาแบบนี้
เท่านี้ก็ทำให้เราพอจะเดาได้ว่า message ตัวไหนที่ทำให้เกิด EXC_BAD_ACCESS
อ่านเพิ่มเติม: Understanding EXC_BAD_ACCESS
Related Link from Roti
เริ่มจากทดลองสร้างโปรแกรมที่ทำให้เกิดปัญหานี้ก่อน โดยเราจะสร้าง 2 method ขึ้นมาดังนี้
- (void) setString{
_myArray = [NSArray arrayWithObject: @"A"];
}
และ
- (void) getString{
NSLog(@"%@", [_myArray objectAtIndex: 0]);
}
กำหนดให้สองเหตุการณ์นี้ทำงานต่อเนื่องกัน เหตุการณ์ละรอบ
เหตุการณ์แรก เมื่อ method setString ทำงานจะสร้าง object ของ NSArray และเก็บไว้ใน instance variable ชื่อ _myArray
เหตุการณ์ที่สอง เมื่อ method getString ทำงาน จะทำการอ่านค่่าจาก _myArray ออกมาแสดง
เมื่อเราสั่งให้โปรแกรมทำงานจะพบ EXC_BAD_ACCESS ออกมาทาง debugger ดังนี้
Program received signal: “EXC_BAD_ACCESS”.
เหตุผลก็เพราะว่า object ที่ได้จาก method setString จะเป็น autorelease object ดังนั้นแน่นอนว่ามันจะถูกส่งเข้าไปอยู่ใน autorelease pool และถูก release ทิ้งไปเมื่อจบรอบแรกโดยอัตโนมัติ ซึ่งเหตุการณ์จริงอาจไม่ได้หาต้นเหตุของปัญหาง่ายแบบนี้ก็ได้
วิธีตามหาต้นตอของ EXC_BAD_ACCESS เราจะกำหนด parameter ให้กับ Executables ที่อยู่ด้านซ้ายของ xcode window ให้ double click และเลือก get info และไปที่ tab Arguments จากนั้นเพิ่ม NSZombieEnabled และกำหนดค่าเป็น YES เข้าไปดังนี้
NSZombieEnabled เป็น parameter ที่ช่วยบอกว่ามี message ไหนส่งไปหา object ที่ถูก deallocate แล้ว
จากนั้นลองรันโปรกรมเดิมใหม่แทนที่จะโดนตอบกลับมาด้วย EXC_BAD_ACCESS (ซึ่งไม่ช่วย hint อะไรเท่าไหร่นัก) อีก ก็จะได้ผลออกมาแบบนี้
*** -[CFArray objectAtIndex:]: message sent to deallocated instance 0x4b1dd80
เท่านี้ก็ทำให้เราพอจะเดาได้ว่า message ตัวไหนที่ทำให้เกิด EXC_BAD_ACCESS
อ่านเพิ่มเติม: Understanding EXC_BAD_ACCESS
Related Link from Roti

0 comments:
Post a Comment