在块崩溃中分配NSError的调用方法

时间:2017-08-28 16:03:28

标签: objective-c cocoa automatic-ref-counting objective-c-blocks

我想了解为什么会因EXC_BAD_ACCESS错误而崩溃。它从方法调用返回正常,但随后在[self runMethodThatAssignsError:&error]上立即崩溃。

found a similar post here,但它没有解释发生了什么,而且相当陈旧。

- (void)checkError {
    NSError *error;
    [self runMethodThatAssignsError:&error]; // crashes after returning
    NSLog(@"success");
}

- (BOOL)runMethodThatAssignsError:(NSError **)error {
    [@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        *error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
    }];
    return NO;
}

1 个答案:

答案 0 :(得分:8)

在Instruments中运行示例代码,似乎-[NSArray enumerateObjectsUsingBlock:]将其块包装在自动释放池中。由于默认情况下NSError **指针被隐式假设为__autoreleasing,因此当NSError对象分配给*error时,会自动释放-[NSArray enumerateObjectsUsingBlock:]指针,因此被- (BOOL)runMethodThatAssignsError:(NSError **)error { __block NSError *_error = nil; [@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { _error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}]; }]; if (error) *error = _error; return NO; } 收获自动释放池。

有两种方法可以解决这个问题。第一个是在块之外使用局部变量,以使ARC在枚举完成之前保留它:

error

或者,您可以将__strong参数声明为NSError,这样可以防止- (BOOL)runMethodThatAssignsError:(NSError * __strong *)error { [@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if (error) *error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}]; }]; return NO; } 首先放入自动释放池中。请注意,只有在此方法的客户端始终使用ARC时才应该这样做,因为否则它可能会导致错误泄漏,因为客户端不希望发布它们,因为这种方法是非常规的。

#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/edmonds_karp_max_flow.hpp>


using namespace boost;


typedef adjacency_list_traits < vecS, vecS, directedS > Traits;

typedef adjacency_list < vecS, vecS, directedS,

    property < vertex_name_t, std::string,
    property < vertex_index_t, int,
    property < vertex_color_t, boost::default_color_type,
    property < vertex_distance_t, double,
    property < vertex_predecessor_t, Traits::edge_descriptor > > > > >,

    property < edge_index_t, int, 
    property < edge_capacity_t, double,
    property < edge_weight_t, double, 
    property < edge_residual_capacity_t, double,
    property < edge_reverse_t, Traits::edge_descriptor > > > > > > Graph;

int main()
{
    Graph g;
    property_map<Graph, vertex_index_t>::type v = get(vertex_index, g);
    property_map<Graph, edge_index_t>::type e = get(edge_index, g);
    property_map<Graph, edge_capacity_t>::type cap = get(edge_capacity, g);
    property_map<Graph, edge_weight_t>::type cost = get(edge_weight, g);
    property_map<Graph, edge_residual_capacity_t>::type rescap = get(edge_residual_capacity, g);
    property_map < Graph, edge_reverse_t >::type rev = get(edge_reverse, g);

    int nonodes = 4;

    for (int i = 0; i < nonodes; i++) {
        Traits::vertex_descriptor vd;
        vd = add_vertex(g);
        assert(v[vd] == i);//(Q1)Here, v[vd] = i; produces an error. Is there any other way to assign integer indices to vertices?
    }

    Graph::vertex_iterator vertexIt, vertexEnd;
    tie(vertexIt, vertexEnd) = vertices(g);

    //Create edges
    Traits::edge_descriptor edf, edb;//Max flow algorithms seem to want both forward and backward edges. edf is for forward, edb is for backward

//Q2. All of the add_edge() functions below do not seem to add any edges to the graph, leading to a run time error when boykov_kolmogorov_max_flow() is finally called.
    edf = (add_edge(*(vertexIt+0), *(vertexIt + 1), g)).first;
    edb = (add_edge(*(vertexIt + 1), *(vertexIt + 0), g)).first;
    e[edf] = 0;
    e[edb] = 1;
    cap[edf] = 4;
    cap[edb] = 4;

    edf = (add_edge(*(vertexIt + 0), *(vertexIt + 2), g)).first;
    edb = (add_edge(*(vertexIt + 2), *(vertexIt + 0), g)).first;
    e[edf] = 2;
    e[edb] = 3;
    cap[edf] = 4;
    cap[edb] = 4;

    edf = (add_edge(*(vertexIt + 1), *(vertexIt + 3), g)).first;
    edb = (add_edge(*(vertexIt + 3), *(vertexIt + 1), g)).first;
    e[edf] = 4;
    e[edb] = 5;
    cap[edf] = 4;
    cap[edb] = 4;

    edf = (add_edge(*(vertexIt + 2), *(vertexIt + 3), g)).first;
    edb = (add_edge(*(vertexIt + 3), *(vertexIt + 2), g)).first;
    e[edf] = 6;
    e[edb] = 7;
    cap[edf] = 4;
    cap[edb] = 4;

    double flow = boykov_kolmogorov_max_flow(g, *(vertexIt + 0), *(vertexIt + 3));
    return 0;
}