核心数据管理对象是否应该在托管对象上下文的`performBlock:`调用中发生?

时间:2016-05-16 18:11:21

标签: ios objective-c multithreading core-data nsmanagedobject

我最近开始尝试使用Core Data的更新performBlock:构建托管对象上下文。使用这种类型的MOC时,我们应该使用performBlockAndWait:initWithEntity:insertIntoManagedObjectContext:来“确保在为上下文指定的队列上执行块操作。”

作为其中的一部分,我在performBlock:块中移动了[private performBlock:^{ for (NSDictionary *jsonObject in jsonArray) { NSManagedObject *mo = ... ; //Managed object that matches the incoming JSON structure } NSError *error = nil; if (![private save:&error]) { NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]); abort(); } }]; 的托管对象创建调用,以便在MOC的专用队列上运行。

这符合Apple's Core Data Concurrency文章中显示的策略:

void

found myself初始化+ (void)managedObjectFromJSON:(NSDictionary *)json completion:(void (^)(XYZManagedObject *object))completion; 方法中的托管对象,这些方法实际上在完成块中返回新创建的对象。

performBlock:

与简单地从JSON解析方法返回对象相比,此体系结构引入了复杂性。我似乎也遇到了与此设计相关的并发问题/崩溃,可能是在这些完成块构造函数中链接在一起的关系管理对象的异步加载中。

我的每个托管对象执行类似下面的操作,通过在[managedObjectContextPrivateQueue performBlock:^{ NSEntityDescription *entity = [NSEntityDescription entityForName:@"entity" inManagedObjectContext:managedObjectContextPrivateQueue]; XYZManagedObject *managedObject = [[XYZManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:managedObjectContextPrivateQueue]; [managedObjectContextPrivateQueue save:&error] completion(managedObject); }]; 块内调用的完成块返回创建的对象。

performBlock:

或者,托管对象是否可以在NSEntityDescription块之外创建,并且只能插入/保存操作?请注意,NSEntityDescription *entity = [NSEntityDescription entityForName:@"entity" inManagedObjectContext:managedObjectContextPrivateQueue]; XYZManagedObject *managedObject = [[XYZManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; [managedObjectContextPrivateQueue performBlock:^{ [managedObjectContextPrivateQueue insertObject:managedObject]; [managedObjectContextPrivateQueue save:&error] }]; return managedObject; 方法确实需要访问块外的MOC。

performBlockAndWait:

或者,也许我应该使用performBlock:等待块运行,然后直接从方法返回Managed Object而不是从完成块返回。

当应通过public class DrawPieCharts{ private final int[] COLORS = {0xff000000, 0xaa000000, 0xffff0000, 0xffff8800, 0xffffff00, 0xff00ff00, 0xff00dd00, 0xff00bb00, 0xff009900};//alpha r g b ImageView[]chart_image=new ImageView[3]; TextView[]chart_text=new TextView[3]; String chart_data; int[]chart_labels=new int[3]; public DrawPieCharts(ImageView[] chart_image, TextView[] chart_text, String chart_data){ this.chart_image=chart_image; this.chart_text=chart_text; this.chart_data=chart_data; if(chart_data == null){return;} try{ JSONObject obj = new JSONObject(chart_data); // String charts="{\"charts\":[{\"chart_value\":10000, \"colors\":[4,5,6,7,0], \"slices\":[3000,3500,2500,1000,300]},{\"chart_value\":5000, \"colors\":[1,4,0], \"slices\":[4000,4500,300]},{\"chart_value\": 54.2, \"colors\":[4,0], \"slices\":[6000,4000]}]}"; JSONArray jcharts = obj.getJSONArray("charts"); for (int i = 0; i < jcharts.length(); i++){ JSONObject chartData = jcharts.getJSONObject(i); chart_labels[i] = chartData.getInt("value"); //convert to normal array JSONArray jcolors = chartData.getJSONArray("colors"); int[] colors = new int[jcolors.length()]; for (int c = 0; c < jcolors.length(); c++){ colors[c] =COLORS[jcolors.getInt(c)]; } //convert to normal array JSONArray jslices = chartData.getJSONArray("slices"); int[] slices = new int[jslices.length()]; for (int s = 0; s < jslices.length(); s++){ slices[s] = jslices.getInt(s); } // Draw pie chart DrawPieChart(chart_image[i], chart_text[i], colors, slices, String.valueOf(chart_labels[i])); } } catch (JSONException e){ e.printStackTrace(); }; } private void DrawPieChart(ImageView ImageView,TextView TextView, int [] colors,int [] slices, String label){ Bitmap bmp = Bitmap.createBitmap(ImageView.getDrawable().getIntrinsicHeight(),ImageView.getDrawable().getIntrinsicHeight(), Bitmap.Config.ARGB_8888);//w h config float scale = bmp.getDensity(); Canvas canvas = new Canvas(bmp); int width=bmp.getWidth()-2; int height=bmp.getHeight()-2; int centerX=width/2; int centerY=height/2; RectF box = new RectF(2,2,width,height); //get value for 100% int sum = 0; for (int slice : slices){ sum += slice; } //initalize painter Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(1f); paint.setStyle(Paint.Style.FILL_AND_STROKE); float start = -90;//start at top of pie //draw slices for(int i =0; i < slices.length; i++){ paint.setColor(colors[i]); float angle; angle = ((360f / sum) * slices[i]); canvas.drawArc(box, start, angle, true, paint); paint.setColor(0xFF000000); start += angle; } start = -90;//start at top of pie //draw labels - Must be drawn on top of slices for(int i =0; i < slices.length-1; i++){ float angle; angle = ((360f / sum) * slices[i]); paint.setColor(0xFF000000); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize((int) (scale/3));// text size in pixels //paint.setShadowLayer(1f, 0f, 1f, 0x66FFFFFF);// text shadow float radius = centerX/1.5f;//Center text inside pie slice fat end to pointed end - X int center = (int) (start+angle/2);//Center text inside pie slice fat end, top to bottom - Y int textX = (int)(radius * Math.cos(center * Math.PI / 180F)) + centerX; int textY = (int)(radius * Math.sin(center * Math.PI / 180F)) + centerY; start += angle; if(angle<30){continue;}//too small to print text on, so just skip it. canvas.drawText(String.valueOf(slices[i]), textX, textY, paint); } ImageView.setImageBitmap(bmp); TextView.setText(label); } } 专用队列路由托管对象上下文调用时,应如何创建和返回托管对象?

1 个答案:

答案 0 :(得分:1)

您可以在MOC之外创建托管对象。请参阅f(0) = 1 f(1) = 1 * f(0) = 1 f(2) = 2 f(3) = 1 * f(2) + 1 * f(1) + 1 * f(0) = 4 f(4) = 0 f(5) = 1 * f(4) + 1 * f(3) + 1 * f(2) = 6

但是,您可能不希望这样做。如果要创建一个有条件的对象,这很有用。例如,如果您有一个托管对象代表用户可能编辑的内容,您可以创建一个非托管版本进行编辑,并仅在用户保存更改时插入MOC。这不是最好的方式,但它确实有效。

但是,您的问题实际上是关于MOC的异步操作。我的观点是,最好的办法是查看每个处理托管对象的API,并弄清楚如何使它们正确异步。您绝对应该从方法返回托管对象,除非您知道调用方在同一MOC的-[NSManagedObjectContext insertObject:]内运行。这是因为无法从创建它们的MOC外部(可靠地)访问托管对象。

您可以返回performBlock{AndWait}:,让调用者获取关联的对象。它通常更乏味,效率更低,但它是跨越MOC边界的唯一可靠解决方案。