OSX-NSTableview reloadData method do not load data from sqlite properly - macos

I'm new to objective-c programming.
I'm doing an application to manage data from a sqlite database. It's used to check attendance of students.
As I'v implemented the update button which change registration time of a student, I used reloadData method to refresh the tableview.
However, it doesn't work properly. It did change the view, but not the right cell.
For example, I tried to change the registration time of student A, the method change that of student B.
I debugged it, the database was updated correctly, so I think it is the method wrong.
Can anyone give me a hint on the problem? Any suggestion will be appreciated :)
if ([[self.StartOrEndMatrix.selectedCell title] isEqualToString:#"上课"]) {
changedColumn = 3;
}else if([[self.StartOrEndMatrix.selectedCell title] isEqualToString:#"下课"]){
changedColumn = 4;
}
if ([[self.NameOrNumberMatrix.selectedCell title] isEqualToString:#"按姓名"]) {
Index = 1;
}else if ([[self.NameOrNumberMatrix.selectedCell title] isEqualToString:#"按学号"]){
Index = 0;
}
NSString* whereString = [[NSString alloc] initWithString:[self.RegistraitionTextField stringValue]];
NSString* data = [self presentTime];
[self updateStudentInSqlite:_database table:self.table atChangedColumn:changedColumn withOriginValue:whereString atIndex:Index andNewString:data];
[self updateColumnArrayNamed:self.attributeNameArray[changedColumn] atIndex:changedColumn withValue:data];
[self fullDataToStudentInTable];
[self.InfoTable reloadData];

Related

Core Data Exporting all tables

I have an app that creates individual events and stores them in core data. What I need to do it load one individually and then export it by email. The code below works except it exports every event where I need it to just export the index path selected one. The code does load the appropriate record because the NSLog (#"My record is: %#", currentItem); does display only the settings for that event but when the data is exported to email all events are sent. I need the selected event with the event name to export. Any thoughts?
NSInteger index = exportevent.tag;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
CDBaseItem *rawRecord = [self.fetchedResultsController objectAtIndexPath:indexPath];
CDSurveyItem *surveyItem = [CDSurveyItem castObject:rawRecord];
self.recordEditID = [rawRecord.objectID URIRepresentation];
NSManagedObjectID *objectId = [self.managedObjectContext.persistentStoreCoordinator managedObjectIDForURIRepresentation:self.recordEditID];
TSPItem *currentItem = [self.managedObjectContext objectWithID:objectId];
NSString *eventName = nil;
if (currentItem.eventname) {
eventName = currentItem.eventname;
}
else if (surveyItem.eventname) {
eventName = surveyItem.eventname;
}
[self setSelection:indexPath];
if (self.selection)
{
if (currentItem)
{
NSLog (#"My record is: %#", currentItem);
NSData *export = [CDJSONExporter exportContext:currentItem.managedObjectContext auxiliaryInfo:nil];
MFMailComposeViewController *composeVC1 = [[MFMailComposeViewController alloc] init];
composeVC1 = [[MFMailComposeViewController alloc] init];
composeVC1.mailComposeDelegate = self;
[composeVC1 setSubject:[NSString stringWithFormat:#"Settings From %# Event", eventName]];
[composeVC1 setMessageBody:[NSString stringWithFormat:#"Here is the event settings. Simply press on the attachment and then choose Open in iPIX"] isHTML:NO];
[composeVC1 addAttachmentData:export mimeType:#"application/octet-stream" fileName:[NSString stringWithFormat:#"%#.ipix", eventName]];
[self presentViewController:composeVC1 animated:NO completion:^(void){}];
}
[self setSelection:nil];
}
Your NSLog may be correct, but you're not exporting the thing that you're printing. In this line (which I assume is a reference to this project):
NSData *export = [CDJSONExporter exportContext:currentItem.managedObjectContext auxiliaryInfo:nil];
You're telling CDJSONExporter to export the context, not a single object. You get every object because that is what CDJSONExporter does. It gets everything it can find in the context and gives you a data object. It's not designed to do what you're asking it to do.
If you want to convert a single object to JSON, you could
Roll your own JSON conversion code. Since you know what the object looks like, this would be easy. Or...
Implement Encodable on your model object and then use JSONEncoder to convert to JSON. Or...
Find some other open source project that does what you want, instead of this one which does not.

Collectionview cells won't render with CKAsset

I'm no longer able to render collectionview cells after using data from Cloudkit via CKAssets. I was previously using images loaded in a folder on my desktop just for initial testing. I'm now using Cloudkit and I've created some test records via the CK dashboard using those same images. I was successfully able to query the CK database and retrieve the expected records. I then changed my code to populate the model data for the cells to use the CK data. That data previously came from the images retrieved locally. I can see from logging that I am getting the data from CK successfully, including the images. I can also see from logging that my custom CV cells are no longer getting initialed. From what I can tell, my code looks good based on examples I've seen online.
Can anyone help me with this? Thank you!
Designated initializer in the model...
- (instancetype)initImagesForSelection:(NSString *)selectionType {
self = [super init];
if (self) {
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ImageDescription = 'description'"];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"ImageData" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
// handle the error
if (error) {
NSLog(#"Error: there was an error querying the cloud... %#", error);
} else {
// any results?
if ([results count] > 0) {
NSLog(#"Success querying the cloud for %lu results!!!", (unsigned long)[results count]);
for (CKRecord *record in results) {
ImageData *imageData = [[ImageData alloc] init];
CKAsset *imageAsset = record[#"Image"];
imageData.imageURL = imageAsset.fileURL;
NSLog(#"asset URL: %#", imageData.imageURL);
imageData.imageName = record[#"ImageName"];
//imageData.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageAsset.fileURL]];
imageData.image = [UIImage imageWithContentsOfFile:imageAsset.fileURL.path];
NSLog(#"image size height:%f, width:%f", imageData.image.size.height, imageData.image.size.width);
[self.imageDataArray addObject:imageData];
}
NSLog(#"imageDataArray size %lu", (unsigned long)[self.imageDataArray count]);
}
}
}];
}
return self;
}
Collectionview viewcontroller which worked perfectly before pulling the data from Cloudkit...
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell"; // string value identifier for cell reuse
ImageViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSLog(#"cellForItemAtIndexPath: section:%ld row:%ld", (long)indexPath.section, (long)indexPath.row);
cell.layer.borderWidth = 1.0;
cell.layer.borderColor = [UIColor grayColor].CGColor;
ImageData *imageData = [self.imageLoadManager imageDataForCell:indexPath.row];
cell.imageView.image = imageData.image;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
return cell;
}
Ok, I figured this out. My code was actually working. The collectionview was not displaying due to a multithreading/asynchronous download issue with the data from cloudkit. I hit the camera button to take a pic, which refreshed the CV and everything in the CV appeared. I just need to use multithreading so things start rendering while the images are downloading.

Push query object to view controller

I have a query that grabs 10 objects, and I am trying to have an action that shows you a window with more information on the object selected, I am just new to Xcode and cannot figure out how to push the information to the new view controller. Here is the code I have that creates the query.
PFQuery *query = [PFQuery queryWithClassName:#"Arcade"];
CLLocation *currentLocation = locationManager.location;
PFGeoPoint *userLocation =
[PFGeoPoint geoPointWithLatitude:currentLocation.coordinate.latitude
longitude:currentLocation.coordinate.longitude];
query.limit = 10;
[query whereKey:kPAWParseLocationKey nearGeoPoint:userLocation withinMiles:kPAWWallPostMaximumSearchDistance];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
// Do something with the found objects
int i = 0;
for (PFObject *object in objects) {
if (i >= [self.EventTitles count]) break;//to make sure we only write up to the max number of UILabels available in EventTitles
[(UILabel *)self.EventTitles[i] setText:[object objectForKey:#"name"]];//I assume the "objectId" property of object is an NSString!
i++;
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
and this is the action to push to the new view controller:
-(IBAction)DetailEvent1:(id)sender{
TableDetailViewController *objDetail = [[TableDetailViewController alloc] initWithNibName:#"TableDetailViewController" bundle:nil];
[self addChildViewController:objDetail];
objDetail.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, self.view.bounds.size.height - 0.0f);
[self.view addSubview:objDetail.view];
}
If someone could help me write the one line of code that needs to be added to the DetailEvent1 action so that the chosen object is pushed I would greatly appreciate it.
TableDetailViewController *objDetail =
[[TableDetailViewController alloc]
initWithNibName:#"TableDetailViewController" bundle:nil];
objDetail.query = self.query
In other words, this is the moment you are creating the next view controller. The two view controllers are now in contact (self and objDetail). So this is the moment to pass data across from the one to the other.
Of course, there is no TableDetailViewController property query. Not yet! But you're going to make one, don't you see - so that you can make this exact move.
Oh, and perhaps there is no query property in self either. But you will need one, because you need a way to hold on to the query that you got in that first method so that it is still available to you in the second method. The way to share data between methods of the same object is very often thru a property.
See also this example from my book:
- (void)showItemsForRow: (NSIndexPath*) indexPath {
// create subtable of tracks and go there
TrackViewController *t =
[[TrackViewController alloc] initWithMediaItemCollection:
(self.albums)[indexPath.row]];
[self.navigationController pushViewController:t animated:YES];
}
In that example, I've gone even further: I've actually given TrackViewController a designated initializer so that I can create it and hand it the data all in one line.

UICollectionView reloadItemsAtIndexPaths

I've been trying to wrap my head around the reloadItemsAtIndexPaths method of UICollectionView.
I have an array of objects called objectsArray. When a user scrolls to the bottom of my collection view, I fetch the next batch of objects from the backend and append it to objectsArray by calling [objectsArray addObjectsFromArray:objects]; After doing so, I call [self.collectionView reloadData] which I know is expensive.
I'd like to optimize with the code below but I get an assertion failure when calling reloadItemsAtIndexPaths.
if (self.searchPage == 0) {
parseObjectsArray = [[NSMutableArray alloc] initWithArray:relevantDeals];
[self.collectionView reloadData];
} else {
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for (int i = 0; i < [relevantDeals count]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[indexPaths addObject:indexPath];
}
[parseObjectsArray addObjectsFromArray:relevantDeals];
[self.collectionView reloadItemsAtIndexPaths:indexPaths];
//[self.collectionView reloadData];
}
Error:
* Assertion failure in -[UICollectionView _endItemAnimations], /SourceCache/UIKit/UIKit-2903.2/UICollectionView.m:3716
Any help/tips is greatly appreciated.
Thanks!
It looks like the items being added are new, in other words you are adding items which weren't there before. In that case, just replace reloadItemsAtIndexPaths:indexPaths with insertItemsAtIndexPaths:
[self.collectionView insertItemsAtIndexPaths:indexPaths]; // Use this for newly added rows
//[self.collectionView reloadItemsAtIndexPaths:indexPaths]; // Use this for existing rows which have changed
The assertion error was misleading. It wasn't until after I implemented
#try
{
[self.collectionView insertItemsAtIndexPaths:indexPaths];
}
#catch (NSException *except)
{
NSLog(#"DEBUG: failure to insertItemsAtIndexPaths. %#", except.description);
}
Did I realize was calculating my indexPaths wrong. My index offset for the new objects was off by one making my collectionview think I was adding more objects than I specified in numberOfItemsInSection.
Thanks for all those who attempted to help!
This error often arises when you increase/decrease the number of items in the array but it doesn't match the data source method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Are you updating it appropriately?

paging (horizontal swiping) through multiple uitableviews

I am trying to put a number tables in uiscrollview such that it can swipe through each (paging). This is done on nicely on TweetDeck.
I'm using https://github.com/andreyvit/SoloComponents-iOS/tree/master/ATPagingView
However im struggling to figure out how to do it without leaking memory.
- (UIView *)viewForPageInPagingView:(ATPagingView *)pagingView atIndex:(NSInteger)index {
myTableViewController *t = [[servicesController alloc] init];
t.delegate = self.navigationController; //such that the tableview can call nav controller
t.info = [array objectAtIndex:index]; //Data that is different for every page
return [t.view autorelease];
}
Does anyone have any suggestions as to how I should modify ATPagingView to accomodate for UIViewControllers instead of UIViews? Or any other examples?

Resources