ios viewcontroller 视图图与可变数组一起使用
Posted
技术标签:
【中文标题】ios viewcontroller 视图图与可变数组一起使用【英文标题】:ios viewcontroller view graph live with Mutable Array 【发布时间】:2014-09-30 08:26:35 【问题描述】:早上好,
我尝试实现的是在视图中绘制图形,同时通过数组在 VC 中实时添加数据。
到目前为止,我有一个 VC 和一个有自己的类的视图。在类内部,在 drawRect 内部,我生成随机数,它们在屏幕上显示为点。到目前为止,一切顺利。
我想做的是在 ViewController 中生成数字(或通过外部源获取它们),将它们保存在 mutableArray 中,在类中检索它们并将它们用于图形。
我在 SO 上发现了一个类似的问题,从 2 年前开始,所以没有必要对此发表评论。问题是:我在 FirstViewController 上有一个带有浮点值的数组。我需要将这个数组传递给我的视图
被标记为有效的推荐解决方案是:
在你的 FirstViewController.h 中写
#include <UIKit/UIKit.h>
extern NSArray *yourArray;
在你的 FirstViewController.m 中写
#import "FirstViewController.h"
@interface FirstViewController ()
@end
NSArray *yourArray;
现在您必须在“MyView”-Class 中导入整个 FirstViewController。只需在 MyView.m 中 #import "FirstViewController.h"。完成后,“yourArray”将在 MyView 中可用。
我完全按照它说的去做,然后我初始化我的数组,把值放入其中,在 VC 中使用 NSLog 检查所有工作是否正常,并且确实如此。当我尝试在我的视图中检索一个值并对其进行 NSLog 检索时,它表示数组中的值为(null)。 代码很简单,我几乎没有什么可显示的:
在我的 VC.h 中
extern NSMutableArray *yourArray;
在我的 VC.m 实现中
NSMutableArray *yourArray;
在我的 VC.m viewDidLoad 中
NSMutableArray *yourArray = [[NSMutableArray alloc] init];
[yourArray insertObject:@"Works" atIndex:0];
NSString *object = [yourArray objectAtIndex:0];
NSLog (@"the item in Array in VC is %@", object);
在我看来.m
#import "GraphViewController.h"
然后我尝试添加:
NSString *object = [yourArray objectAtIndex:0];
NSLog (@"the item in Array in View is %@", object);
在 (void)awakeFromNib 中,在 (id)initWithFrame:(CGRect)frame 中,在 (void)updateValues 和 (void)drawRect:(CGRect)rect 中
它在我放置的任何地方都不起作用。我完全不知所措。
有人可以指点我正确的方向吗?
谢谢,
==============================================
【问题讨论】:
【参考方案1】:我会一点一点地尝试。
你有: UIViewController 的子类称为 GraphViewController。 UIView 的一个子类,称为 MyGraphView。 故事板。
在您的故事板中,您有一个 UIViewController 场景,其中包含一个 UIView 对象。 在“身份检查器”中,您已将 UIViewController 场景“自定义类”字段设置为 GraphViewController。正确的? 同样在 Identity Inspector 中,您已将 UIView 对象自定义类字段设置为 MyGraphView。对吗?
因此,当您从 View 对象右键单击并拖动到 GraphViewController 的头文件时,弹出窗口会出现,您可以输入属性名称,并且该弹出窗口的“Type”字段已设置为 MyGraphView。对吗?
设置 IBOutlet 属性后,您可以在 storyboard 中选择 GraphViewController 并显示 Connections Inspector 并看到存在一个名为 MyGraphView 的引用 Outlet 连接到 GraphViewController。?
所以如果所有这些都是真的,那么你的 viewController 和 View 就在 storyboard 中设置好了。
GraphViewController 有一个名为 yourArray 的 NSMutableArray 属性。 GraphViewController 有一个名为 myView 的 MyGraphView 属性。 MyGraphView 有一个名为 graphDataArray 的 NSArray 属性。
因此,在您的 GraphViewController 中将此方法粘贴到 -viewDidLoad 上方。
-(void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
self.yourArray = [@[@"Testing"] mutableCopy];
if (self.myView == nil)
NSLog(@"The Instance of MyGraphView called MyView does not exist");
return;
else
NSLog(@"The Instance of MyGraphView called MyView exists %@",self.myView);
self.myView.graphDataArray = [self.yourArray copy];
if (self.myView.graphDataArray == nil)
NSLog(@"GraphDataArray is nil");
else
NSLog(@"Object at index 0 = %@",self.myView.graphDataArray[0]);
NSLog(@"MyGraphView can now receive arrays from GraphViewController :]");
【讨论】:
对您提出的所有问题都是肯定的。我最终把 self.myView.graphDataArray = [self.yourArray copy];在 myViewDidLoad 除了你在 viewDidAppear 中运行的测试之外,我有相同的代码。我不认为它来自VC。我保留了您的 viewDidAppear 并删除了 viewDidLoad 中的内容,然后在 myGraphView 中的 drawRect 中,我输入了 if ([self.graphDataArray count] == 0) NSLog (@"view graph 中的项目数 %lu", (unsigned long)[self.graphDataArray 计数]);返回;并记录:MyGraph5[5932:60b] 视图图 0 中的项目数,尽管我们将 @"Testing" 放入其中 运行时 viewDidAppear 的 nslog 输出是什么? MyGraphView 存在吗? 存在名为MyView的MyGraphView实例好的,让我们先让数组在 GraphViewController 中工作,然后再考虑视图。
从其他堆栈溢出问题中摆脱您使用的代码并为您提供新的东西更容易。
// in GraphViewController.m file
#import "GraphViewController.h"
@interface GraphViewController ()
// create a property that you can access elsewhere using self.yourArray
@property (nonatomic, strong) NSMutableArray *yourArray;
@end
@implementation GraphViewController
-(void)viewDidLoad
[super viewDidLoad];
self.yourArray = [@[@"Works1",@"Works2",@"StillWorks"] mutableCopy];
NSLog (@"the item in Array in VC is %@", self.yourArray[0]);
NSLog (@"the item in Array in VC is %@", self.yourArray[1]);
NSLog (@"the item in Array in VC is %@", self.yourArray[2]);
视图类
// In AAAView.h declare this property
@property (nonatomic, strong) NSArray *graphDataArray;
然后,当您想将数组从 ViewController 传递到您的视图时,您可以这样做
// yourAAAView is the instance of the view you have in your ViewController
yourAAAView.graphDataArray = [self.dataArray copy];
//*********************************************
在 GraphViewController 中为您的视图创建一个 IBOutlet,我们将其命名为“myView” 在 -viewDidLoad 中,使用绘制点所需的值填充 yourArray。 如果您使用浮点数、双精度数或整数等,则需要先将值包装在 NSNumber 中,然后才能将它们添加到数组中。 如果您使用的是 CGPoints,则需要先将值包装在 NSValue 中,然后才能将它们添加到数组中 一旦数组的所有值都传递给 self.myView self.myView.graphDataArray = self.yourArray; 在 YourView 类 -drawRect 中,您需要从 self.graphDataArray 中获取值并使用它们来绘制您的点。 检查 self.graphDataArray 是否为 nil,如果是则返回。尝试使用不存在的数组毫无意义。 我猜您最初使用了 for 循环,因此您需要执行以下操作:.
for(int i = 0; i< [self.graphDataArray count]; i++)
// get object (NSNumber or NSValue) from array
// NSNumber *num = self.graphDataArray[i];
// NSValue *val = self.graphDataArray[i];
// unwrap the value you stored in the object (float or CGpoint etc)
// use those values to draw the dots the same way you did before
【讨论】:
您好克里斯蒂安,感谢您的回答。是的,这在 VC 中没有问题,它确实可以正常工作。 我不确定我是否完全明白,如果你能解释一下。这种方法的目的是什么? -(void)acceptArrayOfGraphData:(NSArray*)array self.graphDataArray = array; [yourView acceptArrayOfGraphData:self.yourArray];进入我的VC,对吧?事实上,我在两者中都进行了尝试,并在两者中都收到了错误消息。如果我查看它,它会说找不到您的数组。如果我放入 VC,它说不知道选择器的类方法 acceptArrayOfGraphData 如何获取数组的值?就像我在 VC 中做的一样 NSLog 呢?在我的视图的哪一部分? 对不起,我可能把它弄得比你需要的更复杂。我会编辑它。 要从 AAAView 中的数组中获取值,您可以使用 NSString *aString = self.graphDataArray[0];和我在 NSLog 中所做的一样。 对不起,我今天一定很厚......或者一般来说:-)但我不明白。我在我的 VC 中有一个名为 YourArray 的可变数组(顺便说一下 Works1、Works2 的馈送......这种方式会给出警告消息,因为不兼容的指针类型从 NSArray 分配给 NSMutable 数组)。然后在 myView 中,我创建了一个名为 GraphDataArray 的 NSArray(非可变)。 yourAAAView 是我在 VC 中的视图实例的故事是什么?我所做的只是为了在我的 Storyboard 上显示一个视图并将其附加到我创建的 ViewClass 上。我没有创建该视图的任何实例。我应该有吗?【参考方案3】:如果您要将这些点渲染到视图,则无需维护单独的点数组。 UIBezierPath 维护自己的点数组。不要将点数组传递给它,而是将点传递给 UIBezierPath 对象点数组。
以下 UIView 代码是我用来实时实时(每秒 30 次)呈现图形的全部内容,因为我的 Core Data 数据库会使用新记录进行更新:
//
// GraphView.h
// DemonNetDAQClient
//
// Created by James Bush on 5/3/17.
// Copyright © 2017 James Bush. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
typedef void(^PointBlock)(id path);
@interface GraphView : UIView
- (void)addPoint:(PointBlock)block;
@end
在 UIView 头文件中,我设置了一个将临时 UIBezierPath 对象传递给 UIViewController 的块,这将创建一个路径以附加到在 UIView 中绘制图形的 UIBezierPath。
这是我的 GraphView.m:
//
// GraphView.m
// DemonNetDAQClient
//
// Created by James Bush on 5/3/17.
// Copyright © 2017 James Bush. All rights reserved.
//
#import "GraphView.h"
#import "GraphViewController.h"
@interface GraphView ()
@property (strong, nonatomic) UIBezierPath *graph;
@end
@implementation GraphView
- (void)drawRect:(CGRect)rect
[[UIColor redColor]setStroke];
[self.graph stroke];
- (void)addPoint:(PointBlock)block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
UIBezierPath *graphTmp = [UIBezierPath bezierPath];
[graphTmp moveToPoint:[self.graph currentPoint]];
block(graphTmp);
[self.graph appendPath:graphTmp];
);
- (UIBezierPath *)graph
UIBezierPath *g = self->_graph;
if (!g)
g = [UIBezierPath bezierPath];
[g moveToPoint:CGPointMake(0.0, CGRectGetMidY(self.frame))];
self->_graph = g;
return g;
@end
每当一个新对象插入到我的核心数据数据库中时(由我的 NSFetchedResultsControllerDelegate/UIViewController 检测到),就会调用 addPoint 方法。调用时,UIViewController 会传递一个块,其中包含对在 UIView 中创建的临时 UIBezierPath 对象的引用,它将向该对象添加一个点。当块返回给 UIView 方法时,新配置的临时 UIBezierPath 对象将附加到由 UIView 呈现的 UIBezierPath。您的所有点数据都由该 UIBezierPath 对象维护。
注意 |我编写了一个单独的方法来创建 UIBezierPath 对象,以将它的第一个点设置为图形视图中的正确位置,尽管我可以在 awakeFromNib 方法中的两行中完成此操作。我这样做是为了与情节提要上的视图和以编程方式实例化的视图兼容(没有情节提要就不能调用 awakeFromNib)。
以下是相关的 UIViewController 代码,它从 NSFetchedResultsController 获取点数据(我相信你已经认识并且已经熟悉了,使用过表格视图控制器——都是一样的):
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
switch(type)
case NSFetchedResultsChangeInsert:
Metric *metric = (Metric *)anObject;
double measurement = metric.metricMeasurement;
CGFloat y = [self convertMetricToPoint:measurement];
[(GraphView *)self.graphView addPoint:^(id path)
CGPoint newPoint = CGPointMake([path currentPoint].x + 1.0, y);
[path addLineToPoint:newPoint];
[path moveToPoint:newPoint];
];
break;
case NSFetchedResultsChangeDelete:
break;
case NSFetchedResultsChangeUpdate:
break;
case NSFetchedResultsChangeMove:
break;
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
[self.graphView setNeedsDisplay];
- (CGFloat)convertMetricToPoint:(double)metric
double maxPointValue = ([(NSNumber *)[self valueForKeyPath:@"fetchedResultsController.fetchedObjects.@max.metricMeasurement"] doubleValue]);
double normalizedMetric = (metric / maxPointValue) * self.graphView.frame.size.height;
return (CGFloat)normalizedMetric;
您希望看到它的实际效果吗? Here's a video:
<iframe width="1280" height="720" src="https://www.youtube.com/embed/JYF2ZSEgOrg" frameborder="0" allowfullscreen></iframe>
【讨论】:
以上是关于ios viewcontroller 视图图与可变数组一起使用的主要内容,如果未能解决你的问题,请参考以下文章
ios:在模型视图上推送另一个 ViewController
IOS在ViewController中以编程方式删除子视图的位置
iOS自动布局:在ViewController中获取视图内的视图宽度