如何通过键和值获取对象
how to get object by key and value
我有一个名为 masterMessages 的对象,其中填充了名为消息的对象。每个消息对象有五个键:
- objectId
- 发件人编号
- 发件人姓名
- 消息正文
- 时间戳
基本上我现在正在做的是在这个名为 masterMessages 的对象中查询发送给我的用户的所有消息。然后我使用:
self.senderIds = [masterMessages valueForKeyPath:@"@distinctUnionOfObjects.senderId"];
在名为 senderIds 的数组中获取所有不同的发件人 ID (senderId)。有了这个,我将填充我的对话 table。但我想用发件人姓名 (senderName) 而不是 senderIds 填充它。我只在两个用户具有相同名称的情况下才这样做。
我正在寻找:
- 我怎么说 "get valueForKey:@"senderName" 对于这个 senderId
和
- 是否有更好的方式来填充我的对话table?
这是我的代码:
注意:我正在使用 parse.com
-(void)viewWillAppear:(BOOL)animated{
NSString *userId = [[PFUser currentUser] objectId];
PFQuery *query = [PFQuery queryWithClassName:@"lean"];
[query whereKey:@"recipientId" equalTo:userId];
[query orderByDescending:@"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
else {
// We found messages!
masterMessages = objects;
NSLog(@"self.messages = %@", masterMessages);
self.senderIds = [masterMessages valueForKeyPath:@"@distinctUnionOfObjects.senderId"];
NSLog(@"self.senderIds = %@", self.senderIds);
[self.tableView reloadData];
}
}];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.senderIds count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
NSLog(@"self.senderIds = %@", self.senderIds);
NSString *senderDisplayName = [self.senderIds objectAtIndex:indexPath.row];
NSLog(@"sender = %@", senderDisplayName);
cell.textLabel.text = senderDisplayName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedId = [self.senderIds objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"ShowMissionMessage" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"ShowMissionMessage"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
MissionChat *missionchatviewcontroller = (MissionChat *)segue.destinationViewController;
missionchatviewcontroller.selectedId = selectedId;
missionchatviewcontroller.masterMessages = masterMessages;
}
}
问题中有几个问题,一个是如何取消引用 PFObjects,我们已经解决了 。这个问题的其余部分是关于 (a) 如何使用解析对象构建数据源以支持 table 视图,以及更难的问题 (b) 如何从相关对象获取信息。
从 (b) 开始,比较难的一个:有几种方法可以关联对象。您选择一个包含相关对象 ID 的字符串类型的列是直观的(特别是如果您有 SQL 背景),但最不可取。对一对一或小型一对多关系建模的更好(最佳)方法是使用指针(如果是一对多,则为指针数组)。
所以我认为您的 senderId 和 recipientId 字符串列应该替换为称为发件人和收件人的指针类型列。这样做的巨大优势是能够急切地获取消息(或 "lean" 在您的术语中)查询中的那些指向的对象。
进行更改后,您的新改进查询如下所示:
PFQuery *query = [PFQuery queryWithClassName:@"lean"];
// notice the first change for the better here:
[query whereKey:@"recipient" equalTo:[PFUser currentUser]];
[query orderByDescending:@"createdAt"];
// notice the really valuable feature here:
[query includeKey:@"sender"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// using the array of PFObjects understanding from your other question...
for (PFObject *pfObject in objects) {
NSString *messageBody = [pfObject objectForKey:@"messageBody"];
// these lines here are the punch line:
PFUser *sender = [pfObject objectForKey:@"sender"];
NSString *senderName = [sender username];
NSLog(@"The message %@ was sent by %@", messageBody, senderName);
}
}];
上面要注意的重要一点是,我们能够为 @"sender" 列请求结果对象,并且因为您已将其更改为指针,并且因为您已经完成了 includeKey在查询中,现在获取了完整的对象(例如,包括 PFUser 用户名)。
现在是简单的问题(a)。现在您已经拥有来自服务器的数据,table 的数据源只不过是返回的对象。换句话说,扔掉 senderIds
数组并将其替换为:
@property(nonatomic, strong) NSArray *messages;
您的查找块变得微不足道:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
self.messages = objects;
}];
为numberOfRowsInSection
回答messages.count
,然后从cellForRowAtIndexPath
...
中的对象中选择你需要的东西
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
PFObject *message = self.messages[indexPath.row];
NSString *messageBody = [message objectForKey:@"messageBody"];
PFUser *sender = [message objectForKey:@"sender"];
NSString *senderName = [sender username];
cell.textLabel.text = senderName;
return cell;
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
var result = getObjects(obj, 'category_id', valu.category_id);
console.log(result);
function findObjectByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
var obj = findObjectByKey(objArray, 'id', 3);
//ES6
var obj = objArray.find(function (obj) { return obj.id === 3; });
我有一个名为 masterMessages 的对象,其中填充了名为消息的对象。每个消息对象有五个键:
- objectId
- 发件人编号
- 发件人姓名
- 消息正文
- 时间戳
基本上我现在正在做的是在这个名为 masterMessages 的对象中查询发送给我的用户的所有消息。然后我使用:
self.senderIds = [masterMessages valueForKeyPath:@"@distinctUnionOfObjects.senderId"];
在名为 senderIds 的数组中获取所有不同的发件人 ID (senderId)。有了这个,我将填充我的对话 table。但我想用发件人姓名 (senderName) 而不是 senderIds 填充它。我只在两个用户具有相同名称的情况下才这样做。
我正在寻找:
- 我怎么说 "get valueForKey:@"senderName" 对于这个 senderId
和
- 是否有更好的方式来填充我的对话table?
这是我的代码:
注意:我正在使用 parse.com
-(void)viewWillAppear:(BOOL)animated{
NSString *userId = [[PFUser currentUser] objectId];
PFQuery *query = [PFQuery queryWithClassName:@"lean"];
[query whereKey:@"recipientId" equalTo:userId];
[query orderByDescending:@"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
else {
// We found messages!
masterMessages = objects;
NSLog(@"self.messages = %@", masterMessages);
self.senderIds = [masterMessages valueForKeyPath:@"@distinctUnionOfObjects.senderId"];
NSLog(@"self.senderIds = %@", self.senderIds);
[self.tableView reloadData];
}
}];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.senderIds count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
NSLog(@"self.senderIds = %@", self.senderIds);
NSString *senderDisplayName = [self.senderIds objectAtIndex:indexPath.row];
NSLog(@"sender = %@", senderDisplayName);
cell.textLabel.text = senderDisplayName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedId = [self.senderIds objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"ShowMissionMessage" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"ShowMissionMessage"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
MissionChat *missionchatviewcontroller = (MissionChat *)segue.destinationViewController;
missionchatviewcontroller.selectedId = selectedId;
missionchatviewcontroller.masterMessages = masterMessages;
}
}
问题中有几个问题,一个是如何取消引用 PFObjects,我们已经解决了
从 (b) 开始,比较难的一个:有几种方法可以关联对象。您选择一个包含相关对象 ID 的字符串类型的列是直观的(特别是如果您有 SQL 背景),但最不可取。对一对一或小型一对多关系建模的更好(最佳)方法是使用指针(如果是一对多,则为指针数组)。
所以我认为您的 senderId 和 recipientId 字符串列应该替换为称为发件人和收件人的指针类型列。这样做的巨大优势是能够急切地获取消息(或 "lean" 在您的术语中)查询中的那些指向的对象。
进行更改后,您的新改进查询如下所示:
PFQuery *query = [PFQuery queryWithClassName:@"lean"];
// notice the first change for the better here:
[query whereKey:@"recipient" equalTo:[PFUser currentUser]];
[query orderByDescending:@"createdAt"];
// notice the really valuable feature here:
[query includeKey:@"sender"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// using the array of PFObjects understanding from your other question...
for (PFObject *pfObject in objects) {
NSString *messageBody = [pfObject objectForKey:@"messageBody"];
// these lines here are the punch line:
PFUser *sender = [pfObject objectForKey:@"sender"];
NSString *senderName = [sender username];
NSLog(@"The message %@ was sent by %@", messageBody, senderName);
}
}];
上面要注意的重要一点是,我们能够为 @"sender" 列请求结果对象,并且因为您已将其更改为指针,并且因为您已经完成了 includeKey在查询中,现在获取了完整的对象(例如,包括 PFUser 用户名)。
现在是简单的问题(a)。现在您已经拥有来自服务器的数据,table 的数据源只不过是返回的对象。换句话说,扔掉 senderIds
数组并将其替换为:
@property(nonatomic, strong) NSArray *messages;
您的查找块变得微不足道:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
self.messages = objects;
}];
为numberOfRowsInSection
回答messages.count
,然后从cellForRowAtIndexPath
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
PFObject *message = self.messages[indexPath.row];
NSString *messageBody = [message objectForKey:@"messageBody"];
PFUser *sender = [message objectForKey:@"sender"];
NSString *senderName = [sender username];
cell.textLabel.text = senderName;
return cell;
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
var result = getObjects(obj, 'category_id', valu.category_id);
console.log(result);
function findObjectByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
var obj = findObjectByKey(objArray, 'id', 3);
//ES6
var obj = objArray.find(function (obj) { return obj.id === 3; });