为什么NSInvocation返回值会创建一个僵尸?

时间:2019-06-07 09:13:58

标签: objective-c nszombie nsinvocation

我正在尝试为本地通信构建JavaScript。为此,我需要在JavaScript调用某个类时动态地执行该方法。

我对NSInvocation获取返回值有疑问。使用getReturnValue时,应用程序由于僵尸而崩溃。指示僵尸来自调用方法的返回值的调用。

如果我将 public static void setCourseList(String courseDescription, String courseName, LocalTime courseStart, LocalTime courseEnd, LocalDate courseDate, DayOfWeek courseDay) { Connection conn = null; try { // db parameters // path to db relative to run time directory String url = "jdbc:sqlite:Holiday.db"; String sqlInsertCourse = "INSERT INTO COURSE (Name,Start,End,Date,Day,Description) VALUES (?, ?,?, ?,?, ?,);"; conn = DriverManager.getConnection(url); System.out.println("Connected"); Statement stmt = conn.createStatement(); PreparedStatement pstmt = conn.prepareStatement(sqlInsertCourse); pstmt.setString(1, courseName); String courseStartString = courseStart.toString(); pstmt.setString(2, courseStartString); java.sql.Time courseEndTime = Time.valueOf(courseEnd); pstmt.setTime(3, courseEndTime); java.sql.Date courseDateDate = java.sql.Date.valueOf(courseDate); pstmt.setDate(4, courseDateDate); String courseDayString = courseDay.toString(); pstmt.setString(5, courseDayString); pstmt.executeUpdate(); pstmt.close(); System.out.println("Connection to SQLite has been established."); // create tables if they do not exists stmt.execute(sqlInsertCourse); } catch (SQLException e) { System.out.println(e.getMessage()); } finally { try { if (conn != null) { conn.close(); } } catch (SQLException ex) { System.out.println(ex.getMessage()); } } } 行注释掉,则应用程序不会中断。

我当前正在调用的测试方法会返回{{1} 如果我使调用的选择器方法实现返回一个@@ firstsecond之类的文字字符串,则应用程序也不会中断。

为什么已经执行了调用方法并返回了一个字符串,为什么它需要以任何方式对其进行引用。不是将返回的字符串复制到[invocation getReturnValue:&result];

(NSString *)

尽管 Instruments 中的选择器不同,但结果相同。从这张照片中我了解了我告诉你的。我没有使用乐器的经验。

enter image description here

1 个答案:

答案 0 :(得分:1)

您是ARC的受害者,但不知道NSInvocation的工作方式是通过另一个指针间接修改result。这是here中描述的已知问题。

发生的情况是,生成的对象间接变为等于result,但是ARC无法识别该对象并且永远不会保留它。

NSString是一个类集群。它的有效含义是根据字符串的创建和使用方式在更改下的实现。在obj-c中与之交互时,它的细节被隐藏了,而Apple付出了很多努力,以使其与iOS开发人员无缝连接。您的情况有点特殊。

通常,您会得到:

  1. __NSCFConstantString(例如@"constant")-应用程序生存期的字符串常量,对于您来说,发生可以正常工作,但您从不
  2. NSTaggedPointerString(例如[[@"a"] mutableCopy] copy])-具有内部查找表的优化短字符串。
  3. __NSCFString(例如[@"longString" mutableCopy] copy])长字符串CoreFoundation表示。

随时NSString可能会更改其下的实现,因此您永远不应对此做任何假设。返回后,情况3将立即超出范围并在下一个运行循环中被释放,情况1将永远不会被释放,情况2(?),但可以肯定的是在下一个运行循环中仍然存在。

因此,从根本上说,ARC不够聪明,无法将可能已释放的对象与id result关联,从而遇到了问题。

如何解决?

使用以下之一:

1。

void *tempResult;
[invocation getReturnValue:&tempResult];
id result = (__bridge id) tempResult;

2。

__unsafe_unretained id tempResult;
[invocation getReturnValue:&tempResult];
result = tempResult;

修改

如@newacct在他的评论getReturnValue:中指出的,weak指针未注册,因此在这种情况下不适当。释放对象时,指针不会归零

<罢工> 3。

__weak id tempResult;
[invocation getReturnValue:&tempResult];
result = tempResult;