duplicate data on refresh ios - ios

I've got my reload function reloading data properly, but I'm getting duplicate data. I've tried nil-ing out the changelist in the below spots and had no luck. Should I be nil-ing out the jsonObject? Or am I just putting it in the wrong spot.
Thanks for any help.
- (void)viewDidLoad
{
[super viewDidLoad];
UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to refresh"];
[refresh addTarget:self action:#selector(refreshmytable:) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refresh;
NSURLSessionConfiguration *config =
[NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config
delegate:self
// delegate:nil
delegateQueue:nil];
[self fetchFeed];
}
- (void)refreshmytable:(UIRefreshControl *)refreshControl{
[self fetchFeed]; //Added 12:12 9.16.14
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:#"Updating"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMM d, h:mm a"];
NSString *updated = [NSString stringWithFormat:#" Last Update: %#", [formatter stringFromDate:[NSDate date]]];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:updated];
[refreshControl endRefreshing];
[self.tableView reloadData]; //Added this 11:32 9.16.14
}
- (void)fetchFeed
{
NSString *userEID = MAP_getUsername();
//NSLog(userEID);
NSString *requestString1 = [#"URL" stringByAppendingString:userEID];
NSString *requestString2 = #"&status=pending";
NSString *requestString = [requestString1 stringByAppendingString:requestString2];
//NSLog(requestString);
/*NSString *requestString = #"http://URL";
*/
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask =
[self.session dataTaskWithRequest:req
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
self.changeList = jsonObject[#"List"];
//self.changeList=nil; //tried to add here to remove duplicate data
NSLog(#"%#", self.changeList);
//- add code here to populate BNRItemStore with the change order list.
// - following code should be rewritten in fetchFeed that will load BNRItemStore.
if (self.changeList.count>0) {
for (int i = 0; i < self.changeList.count; i++) {
NSDictionary *coItem = self.changeList[i];
[[BNRItemStore sharedStore]
addItemWithApproverEid:coItem[#"approverEid"]
assignmentGroup:coItem[#"assignmentGroup"]
changeOrder:coItem[#"changeOrder"]
subcategory:coItem[#"subCatagory"]
title:coItem[#"title"]
];
}
}
//NSLog(#"sizeof(NSInteger) = %#", #(sizeof(NSInteger)));
//- end comment
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
//self.changeList=nil; //trying to null out list for refresh non duplicate data
// NSString *json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(#"%#", json);
}];
[dataTask resume];
}
Added BNRITEM.h class
#class BNRItem;
#interface BNRItemStore : NSObject
#property (nonatomic, readonly) NSArray *allItems;
// Notice that this is a class method and prefixed with a + instead of a -
+ (instancetype)sharedStore;
- (BNRItem *)addItemWithApproverEid:(NSString *)aEid
assignmentGroup:(NSString *)aGroup
changeOrder:(NSString *)changeOrder
subcategory:(NSString *)subcategory
title:(NSString *)title;
#end
added BNRitem.m class
interface BNRItemStore ()
#property (nonatomic) NSMutableArray *privateItems;
#end
#implementation BNRItemStore
+ (instancetype)sharedStore
{
static BNRItemStore *sharedStore;
// Do I need to create a sharedStore?
if (!sharedStore) {
sharedStore = [[self alloc] initPrivate];
}
return sharedStore;
}

I believe the issue is in this code:
[[BNRItemStore sharedStore]
addItemWithApproverEid:coItem[#"approverEid"]
assignmentGroup:coItem[#"assignmentGroup"]
changeOrder:coItem[#"changeOrder"]
subcategory:coItem[#"subCatagory"]
title:coItem[#"title"]
You keep adding data to BNRItemStore but you don't remove the old one, there in nothing to do with self.changeList.
You need some way to remove all data before you add the new one, so on the beginning of the method fetchFeed you can call something like this:
[[BNRItemStore sharedStore] removeAllData];
Note I don't know that class BNRItemStore so removeAllData method probably doesn't exists, maybe there is another method to delete all data or maybe you nnd to implement one.
// Extended
I cannot see all of the method in .m file so I don't know where the data are stored by I believe it's stored in privateItems variable, maybe there is some method to remove all object from that array but it's not declared as public.
You can add a method definitions after
+ (instancetype)sharedStore;
in BNRITEM.h:
-(void)removeAllData;
And in BNRITEM.h implement it like that:
-(void)removeAllData {
[self.privateItems removeAllObjects];
}
And as I said before call [[BNRItemStore sharedStore] removeAllData]; at the beginning of fetchFeed method.

Related

Objective-C - Firebase retrieving data from database and populate in table

Database structure
I have a Firebase database setup (please refer to the picture).
I have a "FeedViewController" to display the contents of each post in the database. A user may post one or more posts.
When retrieving these posts from the Firebase snapshot and storing them onto a dictionary, I find that this dictionary's values are not accessible outside of the Firebase's observeEventType function.
My idea was to retrieve these key-value pairs, store them onto a NSObject custom class object (Post *post) and use this object to load the table view for my "FeedViewController". Inside the observeEventType function, I am able to access the object's values, but outside, I'm not. As a result, I don't know how to use these values to populate the table view in my FeedViewController. I understand that this observeEventType function is an asynchronous callback, but I don't know how to access the values of the object and populate my table. I don't have a clue what the dispatch_async(dispatch_get_main_queue() function is doing here. Any help would be highly appreciated. Thanks!
FeedViewController.m
#import "FeedViewController.h"
#import "Post.h"
#import "BackgroundLayer.h"
#import "SimpleTableCell.h"
#import "FBSDKCoreKit/FBSDKCoreKit.h"
#import "FBSDKLoginKit/FBSDKLoginKit.h"
#import "FBSDKCoreKit/FBSDKGraphRequest.h"
#import Firebase;
#import FirebaseAuth;
#import FirebaseStorage;
#import FirebaseDatabase;
#interface FeedViewController()
#property (strong, nonatomic) Post *post;
#end
#implementation FeedViewController
-(void) viewDidLoad {
[super viewDidLoad];
_ref = [[FIRDatabase database] reference];
self.post = [[Post alloc] init];
/*
_idArr = [[NSMutableArray alloc] init];
_postDict = [[NSMutableDictionary alloc] init];
_idDict = [[NSMutableDictionary alloc] init];
_postID = [[NSMutableArray alloc] init];
_userName = [[NSMutableArray alloc] init];
_placeName = [[NSMutableArray alloc] init];
_addressLine1 = [[NSMutableArray alloc] init];
_addressLine2 = [[NSMutableArray alloc] init];
_ratings = [[NSMutableArray alloc] init];
_desc = [[NSMutableArray alloc] init];
_userEmail = [[NSMutableArray alloc] init];
_userIDArray = [[NSMutableArray alloc] init];
*/
[self fetchData];
NSLog(#"Emails: %#", _post.userID);
}
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CAGradientLayer *bgLayer = [BackgroundLayer blueGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];
FIRUser *user = [FIRAuth auth].currentUser;
if (user != nil)
{
//fbFirstName.text = user.displayName;
//fbEmail.text = user.email;
NSURL *photoUrl = user.photoURL;
NSString *userID = user.uid;
//NSString *uploadPath = [userID stringByAppendingString:#"/profile_pic.jpg"];
//NSData *data = [NSData dataWithContentsOfURL:photoUrl];
//ProfilePic.image = [UIImage imageWithData:data];
FIRStorage *storage = [FIRStorage storage];
FIRStorageReference *storageRef = [storage referenceForURL:#"gs://foodsteps-cee33.appspot.com"];
NSString *access_token = [[NSUserDefaults standardUserDefaults] objectForKey:#"fb_token"];
FBSDKGraphRequest *friendList = [[FBSDKGraphRequest alloc]
initWithGraphPath:#"me?fields=friends"
parameters:nil
tokenString: access_token
version:nil
HTTPMethod:#"GET"];
[friendList startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
id result,
NSError *error) {
if(error == nil)
{
//NSLog(#"%#", result);
NSDictionary *dictionary = (NSDictionary *)result;
NSDictionary *dict = [dictionary objectForKey:#"friends"];
_idArray = [[NSMutableArray alloc] init];
for(int i = 0; i < [[dict objectForKey:#"data"] count]; i++) {
[_idArray addObject:[[[dict objectForKey:#"data"] objectAtIndex:i] valueForKey:#"id"]];
}
//NSLog(#"%#", idArray);
}
else {
NSLog(#"%#",error);
}
}];
}
}
-(void) fetchData {
_refHandle = [[_ref child:#"users"] observeEventType:FIRDataEventTypeValue
withBlock:^(FIRDataSnapshot * _Nonnull snapshot)
{
NSDictionary *postDict = snapshot.value;
NSLog(#"%#", postDict);
for( NSString *aKey in [postDict allKeys] )
{
// do something like a log:
_post.userID = aKey;
}
//_post.
//[_post setValuesForKeysWithDictionary:postDict];
[self.tableView reloadData];
}];
NSLog(#"Emails: %#", _post.userID);
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[_ref child:#"users"] removeObserverWithHandle:_refHandle];
}
#end
Post.m
#import "Post.h"
#implementation Post
- (instancetype)init {
return [self initWithUid:#""
andPostid:#""
andUsername:#""
andDesc:#""
andRatings:#""
andPlacename:#""
andAddressLine1:#""
andAddressLine2:#""
andEmail:#""];
}
- (instancetype)initWithUid:(NSString *)userID
andPostid:(NSString *)postID
andUsername: (NSString *)userName
andDesc:(NSString *)desc
andRatings:(NSString *)ratings
andPlacename: (NSString *)placeName
andAddressLine1: (NSString *)addressLine1
andAddressLine2: (NSString *)addressLine2
andEmail: (NSString *)userEmail {
self = [super init];
if(self) {
self.userID = userID;
self.postID = postID;
self.userName = userName;
self.desc = desc;
self.ratings = ratings;
self.placeName = placeName;
self.addressLine1 = addressLine1;
self.addressLine2 = addressLine2;
self.userEmail = userEmail;
}
return self;
}
#end
Your approach is what I tried to do initially. But I had problems accessing it in cellforrowatindexpath. the thing that works for me is.
- (void)configureDatabase :(NSUInteger)postsAmount{
_ref = [[FIRDatabase database] reference];
// Listen for new messages in the Firebase database
_refHandle = [[[[_ref child:#"posts"]queryOrderedByKey] queryLimitedToLast:postsAmount]observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
[_posts insertObject:snapshot atIndex:0];
}];
}
Then in viewdidappear
[self configureDatabase:_numberOfPosts];
then lastly
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FIRDataSnapshot *postsSnapshot = _posts[indexPath.section];
NSDictionary *post = postsSnapshot.value;
//use key values to create your views.
}
also include
#property (strong, nonatomic) NSMutableArray<FIRDataSnapshot *> *posts;
What this does is queries firebase for your values and receives snapshots. those snapshots are then placed in your _posts array and then you can access them in other methods.

SDWebImage displaying wrong images in UITableView

In my iOS app, I'm displaying images inside multiple UITableViewCells. However, it's not displaying the correct images in each cell.
First I load some content from a Feedly stream with the method below:
- (void)loadStreams {
NSString *feedName = [NSString stringWithFormat:#"%#-id", self.category];
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedId = [standardUserDefaults objectForKey:feedName];
NSString *feedPartial = [feedId stringByReplacingOccurrencesOfString:#"/" withString:#"%2F"];
NSString *feedUrl = [NSString stringWithFormat:#"https://sandbox.feedly.com/v3/streams/%#/contents", feedPartial];
NSLog(#"The Feedly url is: %#", feedUrl);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedUrl]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest addValue:accessToken forHTTPHeaderField:#"Authorization"];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
self.continuation = [responseObject objectForKey:#"continuation"];
NSMutableArray *tempStreams = [[NSMutableArray alloc] init];
for (NSDictionary *dic in jsonArray) {
NSLog(#"Dic contains: %#", dic);
NSDictionary *originArray = [dic objectForKey:#"origin"];
NSDictionary *visualArray = [dic objectForKey:#"visual"];
NSArray *alternateArray = [dic objectForKey:#"alternate"];
NSDictionary *alternate = [alternateArray objectAtIndex:0];
NSString *image = [visualArray objectForKey:#"url"];
NSString *title = [dic objectForKey:#"title"];
NSString *author = [dic objectForKey:#"author"];
NSString *date = [dic objectForKey:#"published"];
NSDictionary *contentum = [dic objectForKey:#"content"];
NSString *content = [contentum objectForKey:#"content"];
NSString *owner = [originArray objectForKey:#"title"];
NSString *givenid = [dic objectForKey:#"id"];
NSString *href = [alternate objectForKey:#"href"];
NSDate *publisher = [NSDate dateWithTimeIntervalSince1970:([date doubleValue] / 1000.0)];
NSString *published = publisher.timeAgoSinceNow;
NSDictionary *data = [[NSDictionary alloc] initWithObjectsAndKeys:title, #"title", image, #"imageurl", published, #"published", owner, #"owner", content, #"content", givenid, #"givenid", href, #"href", author, #"author", nil];
Stream *stream = [[Stream alloc] initWithDictionary:data];
[tempStreams addObject:stream];
}
self.streams = [[NSMutableArray alloc] initWithArray:tempStreams];
tempStreams = nil;
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Services"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}];
[operation start];
}
This passes the data to an object called Stream, which consists of the code below:
Stream.h
#import <Foundation/Foundation.h>
#interface Stream : NSObject
#property (strong, nonatomic)NSString *name;
#property (strong, nonatomic)NSString *thumbnail;
#property (strong, nonatomic)NSString *photo;
#property (strong, nonatomic)NSString *published;
#property (strong, nonatomic)NSString *content;
#property (strong, nonatomic)NSString *givenid;
#property (strong, nonatomic)NSString *linky;
#property (strong, nonatomic)NSString *author;
- (id)initWithName:(NSString *)aName
thumbnail:(NSString *)aThumbnail
photo:(NSString *)aPhoto
published:(NSString *)aPublished
content:(NSString *)aContent
givenid:(NSString *)aId
linky:(NSString *)aLinky
author:(NSString *)aAuthor;
- (id)initWithDictionary:(NSDictionary *)dic;
#end
Stream.m
#import "Stream.h"
#implementation Stream
//The designed initializer
- (id)initWithName:(NSString *)aName
thumbnail:(NSString *)aThumbnail
photo:(NSString *)aPhoto
published:(NSString *)aPublished
content:(NSString *)aContent
givenid:(NSString *)aId
linky:(NSString *)aLinky
author:(NSString *)aAuthor{
self = [super init];
if (self) {
self.name = aName;
self.thumbnail = aThumbnail;
self.photo = aPhoto;
self.published = aPublished;
self.content = aContent;
self.givenid = aId;
self.linky = aLinky;
self.author = aAuthor;
}
return self;
}
- (id)initWithDictionary:(NSDictionary *)dic {
self = [self initWithName:dic[#"title"] thumbnail:dic[#"imageurl"] photo:dic[#"imageurl"] published:dic[#"published"] content:dic[#"content"] givenid:dic[#"givenid"] linky:dic[#"href"] author:dic[#"author"]];
return self;
}
- (id)init {
self = [self initWithName:#"Undifined" thumbnail:#"Undifined" photo:#"Undifined" published:#"Undifined" content:#"Undifined" givenid:#"Undifined" linky:#"Undifined" author:#"Undifined"];
return self;
}
#end
And in the end I build a cell like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * reuseIdentifier = #"programmaticCell";
MGSwipeTableCell * cell = [self.tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (!cell) {
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
CGFloat brightness = [UIScreen mainScreen].brightness;
cell.textLabel.text = [self.streams[indexPath.row] name];
cell.detailTextLabel.text = [self.streams[indexPath.row] published];
NSString *imageUrl = [NSString stringWithFormat: #"%#", [self.streams[indexPath.row] photo]];
NSLog(#"Image is: %# and path is: %d", imageUrl, indexPath.row);
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:imageUrl]
placeholderImage:[UIImage imageNamed:#"tile-blue.png"] options:indexPath.row == 0 ? SDWebImageRefreshCached : 0];
cell.delegate = self; //optional
return cell;
}
What happens though, is that it displays the wrong image in a lot of cells and sometimes the same image for a couple of cells. What am I doing wrong here?
These are symptoms of cell reuse. There are two issues you will have to deal with.
(1) you should reset your cell's content before it is reused. To do this you can override prepareForReuse in the cell and nil out the relevant properties (such as cell.imageView). If you don't do this, you will see the old image -after- the cell has been recycled, before SDWebImage has assigned a new image.
(2) as SDWebImage image retrieval is async, the image may arrive after the cell has scrolled off the screen (and recycled with new content. You need to check whether the image is still relevant before assigning it to the imageView. I am not sure if this is possible with the SDWebImage UIImageView category method. You may have to dissect SDWebImage a little . You can get more control over the process using the SDWebImageManager method:
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
You could use it something like this (in CellForRowAtIndexPath)
[[SDWebImageManager defaultManager] downloadImageWithURL:url
options:0
progress:nil
completed:
^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if ([[tableView indexPathForCell:cell] isEqual:indexPath]) {
//image is still valid for this cell
cell.image = image;
}
}];
Push a unique id on the stack before your closure and check it when your closure completes
prepareForReuse
Like this:
func updateArtistImage(url: URL) {
let _eventId = self.event?.id
SDWebImageManager.shared().loadImage(with: url, options: [], progress: nil) { (image, data, error, cacheType, finished, url) in
if self.event!.id == _eventId {
if error == nil {
self.artistImageView.image = image
} else {
self.artistImageView.image = UIImage(named: "error_image")
}
}
}
}
and this:
override func prepareForReuse() {
super.prepareForReuse()
self.artistImageView.image = nil
}

Unable to update position in core data

I need to update position in core data base. When I add object or remove it from that base everything works fine. Problem occurs when I want to update object in that base. The problem is that program throws me:
Thread 1: EXC_BAD_ACCES(code = 2, adres = 0x38).
It's weird because it throws this error but updtades object at core data. I'm using simulator on Xcode 5. I've tried to comment line by line back in code but it hasn't helped anymore. Taking look at the address of the error and the screen shot there is no address compatible with each other. What is wrong?
Code is this:
[self insertPositionRightAfterChangeValues:name rating:[changedRate stringValue] urlMain:[newInsert urlMain] contentUrl:[newInsert contentUrl] coverUrl:[newInsert coverUrl] date:[newInsert date] type:[newInsert type] int:integer];
And the rest of this method:
-(void)insertPositionRightAfterChangeValues:(NSString *)name rating:(NSString *)rating urlMain:(NSString *)urlMain contentUrl:(NSString *)contentUrl coverUrl:(NSString *)coverUrl date:(NSString *)date type:(NSString *)type int:(int)position
{
int motherPosision = position;
//insert new one
NSManagedObjectContext *context2 = [self managedObjectContext];
Kwejki * newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Kwejki" inManagedObjectContext:context2];
newEntry.name = [[NSString alloc] initWithString: name];
newEntry.rating = [[NSString alloc] initWithString: rating];
newEntry.urlMain = [[NSString alloc] initWithString: urlMain];
newEntry.contentUrl = [[NSString alloc] initWithString: contentUrl];
newEntry.coverUrl = [[NSString alloc] initWithString: coverUrl];
newEntry.date = [[NSString alloc] initWithString: date];
newEntry.type = [[NSString alloc] initWithString: type];
NSLog(#"%#", newEntry.name);
NSLog(#"%#", newEntry.rating);
NSLog(#"%#", newEntry.urlMain);
NSLog(#"%#", newEntry.contentUrl);
NSLog(#"%#", newEntry.coverUrl);
NSLog(#"%#", newEntry.date);
NSLog(#"%#", newEntry.type);
NSError *error2;
if (![context2 save:&error2]) {
NSLog(#"Whoops, couldn't save: %#", [error2 localizedDescription]);
}
else{
NSLog(#"SAVED!!!");
}
}
And the screenshot with this error:
UPDATE:
When I comment line where I invoke method to insert new object I get following error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'Kwejki'
UPDATE 2:
#interface Kwejki : NSManagedObject<NSCopying>
#property (nonatomic, strong) NSString * type;
#property (nonatomic, strong) NSString * contentUrl;
#property (nonatomic, strong) NSString * coverUrl;
#property (nonatomic, strong) NSString * rating;
#property (nonatomic, strong) NSString * urlMain;
#property (nonatomic, strong) NSString * date;
#property (nonatomic, strong) NSString * name;
#end
#implementation Kwejki
#synthesize name;
#synthesize date;
#synthesize urlMain;
#synthesize rating;
#synthesize coverUrl;
#synthesize contentUrl;
#synthesize type;
-(Kwejki *)copyWithZone:(NSZone *)zone
{
Kwejki *copyModel = [[Kwejki allocWithZone:zone] init];
if(copyModel)
{
copyModel.name = [self name];
copyModel.date = [self date];
copyModel.urlMain = [self urlMain];
copyModel.rating = [self rating];
copyModel.coverUrl = [self coverUrl];
copyModel.contentUrl = [self contentUrl];
copyModel.type = [self type];
}
return copyModel;
}
#end
-(void)addNewPosition:(ScrollViewViewController *)ScrollController recentlyDownloadedItem:(KwejkModel *)modelTmp
{
if(modelTmp == nil)
{
NSLog(#"YES NULL");
}
else
{
NSLog(#"Not null");
}
Kwejki * newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Kwejki" inManagedObjectContext:self.managedObjectContext];
NSLog(#"%#", [modelTmp getNameOfItem]);
newEntry.name = [[NSString alloc] initWithString:[modelTmp getNameOfItem]];
newEntry.rating = [modelTmp getRateOfPosition];
newEntry.urlMain = [modelTmp getUrlAdress];
newEntry.contentUrl = [modelTmp getContentUrl];
newEntry.coverUrl = [modelTmp getCoverImage];
newEntry.date = [modelTmp getDateOfItem];
if([modelTmp getType] == photo)
{
newEntry.type = #"0";
}
else if([modelTmp getType] == gif)
{
newEntry.type = #"1";
}
else if ([modelTmp getType] == video)
{
newEntry.type = #"2";
}
NSLog(#"%#", newEntry.name);
NSLog(#"%#", newEntry.rating);
NSLog(#"%#", newEntry.urlMain);
NSLog(#"%#", newEntry.contentUrl);
NSLog(#"%#", newEntry.coverUrl);
NSLog(#"%#", newEntry.date);
NSLog(#"%#", newEntry.type);
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
else{
NSLog(#"UDALO SIE!!!");
}
[modelArray insertObject:newEntry atIndex:0];
[self.tableView reloadData];
}
I've tried to overcome this problem just adding new object again as update but it also doesn't helped. How I add new object: I tap long on position, new window opens and there I add new values, invoke from that view method from Main ViewController, and here it crashes. When I add normally object as described above but in separate window everything works. I really don't know what is wrong.
When I see this error it normally mean that I did not setup my NSManageObject correctly.
Things to check:
Add a break point in your insertPositionRightAfterChangeValues method and step through to find where the exception is thrown. (My guess is when your creating your Kwejki object.)
That Kwejki is a subclass of NSManageObject.
That Kwejki entity and class name are correct. (Could you show your .xcdatamodeId entity properties for Kwejki?)
If everything is correct, then for an insanity check I would create the Kwejki object the long way.
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([Kwejki class]) inManagedObjectContext:context2];
Kwejki* newEntry = [[Kwejki alloc] initWithEntity:entity insertIntoManagedObjectContext:context2];
Then you can see if the entity is a problem or your Kwejki is.
P.S. As a helpful suggestion instead of typing in the entity name.
Kwejki * newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Kwejki" inManagedObjectContext:context2];
I would do something like this.
Kwejki * newEntry = [NSEntityDescription entityForName:NSStringFromClass([Kwejki class]) inManagedObjectContext:context2];
This give you a compiler check for entity name.

Populating my tableview with parsed json in a string

Very new to iOS, a bit lost on what to do. I actually HAVE all that I need, I just need help putting said information into my tableview now. I am debugging and everything is correct when I hover over the variables in my "init" function, but when I go down to the function that handles the cells something is just not clicking. Very frustrating having the information you need but don't know how to put it where you want.
I hate coming to SO for these kind of questions but I have exhausted all other options. Before posting on here, I have tried everything. I tried to google other projects that I can reference, did not find any that was iOS 7 or relevant to my project. I apologize for this elementary question, and thank you in advance.
MasterViewController.m
#interface MasterViewController () {
__block NSString * jsonString;
}
#end
#implementation MasterViewController
#synthesize coursesController = _coursesController;
-(void)getJSONString
{
jsonString = [JSONHelper JSONgetString:#"http://iam.colum.edu/portfolio/api/course?json=True"];
}
-(void)initCourses
{
[_coursesController.masterCoursesList
removeLastObject];
NSError *coursesError = nil;
NSArray *coursesNameList =
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error: &
coursesError];
if(coursesError)
NSLog(#"[%# %#] JSON error: %#", NSStringFromClass([self class]),
NSStringFromSelector(_cmd), coursesError.localizedDescription);
NSArray *coursesNames = [coursesNameList objectAtIndex:0];
for (NSString *courseName in coursesNameList) {
NSString *stringToUse = [courseName substringFromIndex:8];
//initialize variables
NSString *name = courseName;
NSInteger *courseid = 00;
NSString *imageUrl = nil;
//add current building to list
[_coursesController masterCoursesListWithName:name AndcourseID:courseid AndimageURL:imageUrl];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CoursesCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Courses *courseAtIndex = [self.coursesController objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:courseAtIndex.courseName];
return cell;
}
CoursesDataController.m
#interface CoursesDataController()
-(void)initializeDefaultDataList;
#end
#implementation CoursesDataController
#synthesize masterCoursesList = _masterCoursesList;
-(void)initializeDefaultDataList
{
NSMutableArray *coursesList = [[NSMutableArray alloc] init];
Courses *course = [[Courses
alloc]initWithName:#"Loading Now..." AndcourseID:00];
[coursesList addObject:course];
}
-(void)setMasterCoursesList:(NSMutableArray *)newCourseList
{
if(_masterCoursesList != newCourseList)
{
_masterCoursesList = [newCourseList mutableCopy];
}
} //this function is created when you create a NSMutableArray MasterCoursesList
-(id)init
{
if (self = [super init])
{
[self initializeDefaultDataList];
return self;
}
return nil;
}
-(NSUInteger) countOfList
{
return [self.masterCoursesList count];
}
-(Courses *)objectInListAtIndex:(NSInteger)theIndex
{
return [self.masterCoursesList objectAtIndex:theIndex];
}
-(void)masterCoursesListWithName:(NSString *)cName
AndcourseID:(NSInteger *)cID
AndimageURL:(NSString *)cURL
{
Courses *courses;
courses = [[Courses alloc] initWithName:cName
AndcourseID:cID
AndimageURL:cURL];
[self.masterCoursesList addObject:courses];
}
-(void)courseName:(NSString *)cName
AndcourseID:(NSInteger *)cID
{
Courses *courses;
courses = [[Courses alloc] initWithName:cName AndcourseID:cID];
[self.masterCoursesList addObject:courses];
}
#end
CoursesDataController.h
#import <Foundation/Foundation.h>
#class Courses;
#interface CoursesDataController : NSObject
#property(nonatomic, copy) NSMutableArray *
masterCoursesList;
-(NSUInteger) countOfList;
-(Courses *)objectInListAtIndex:(NSInteger)theIndex;
- (void)masterCoursesListWithName:(NSString *)cName
AndcourseID:(NSInteger *)cID
AndimageURL:(NSString *)cURL;
- (void)courseName:(NSString *)cName
AndcourseID:(NSInteger *)cID;
#end
JSONHelper.m
+(NSString *)JSONgetString:(NSString *)query
{
NSString* searchURL = [NSString stringWithFormat:query];
NSError* error = nil; //error for NSUSRLConnection
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSURL* URL = [NSURL URLWithString:searchURL];
[request setURL:URL];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setTimeoutInterval:30];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(#"Error performing request %#", searchURL);
return 0;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"jsonString:%#", jsonString);
return jsonString;
}
I have a lot of code posted, however there are only a few lines that really matter for my question. When I hover over "name" in the following line of code [_coursesController masterCoursesListWithName:name AndcourseID:courseid AndimageURL:imageUrl];
I get what I need (it loops through each JSON array and displays each one). But in the function that handles my cells, when I hover over courseName it doesn't say anything.
Courses *courseAtIndex = [self.coursesController objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:courseAtIndex.courseName];
EDITS:
numberOfRowsInSection function in MasterViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.coursesController countOfList];
}
Try this,
in CoursesDataController.m
-(void)initializeDefaultDataList
{
self.masterCoursesList = [[NSMutableArray alloc] init];
Courses *course = [[Courses
alloc]initWithName:#"Loading Now..." AndcourseID:00];
[self.masterCoursesList addObject:course];
}

How to use dispatch_sync correctly?

I am getting twitter time line data from a custom NSObject class and this class has all the coe for calling the API and parse the data.
I am calling this class from my view controller which has a table view and need to populate the tableview with the data coming from twitter. But due to some issues with the dispatch_sync my view controller calls the twitter class and control comes back to the view controller before the Array (which i am using to populate the tableview) is populated with the data.
Here's some code :
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#import "SpinnerController.h"
#import "proAlertView.h"
#import "SBJson.h"
#import <Accounts/Accounts.h>
#import <Twitter/Twitter.h>
#interface TwitterDataLoad : NSObject<UIAlertViewDelegate>
{
NSMutableData * receivedData;
NSArray * results;
NSArray * cellContent;
NSMutableArray * totalContent;
SpinnerController * spinner;
proAlertView * av;
NSString *json_string;
NSDictionary * jsonResults;
SBJsonParser * parser;
NSMutableArray * dataForTable;
}
#property(nonatomic, strong) ACAccount * account;
#property(nonatomic, strong) NSArray * accounts;
#property(nonatomic, strong) ACAccountStore * accountStore;
#property (nonatomic ,retain) SecondViewController * tbView;
- (void)loadData;
#end
#import "TwitterDataLoad.h"
#interface TwitterDataLoad ()
#end
#implementation TwitterDataLoad
#synthesize tbView;
-(id) init {
self = [super init];
if (self) {
[self loadData];
}
return self;
}
- (void)loadData
{
dataForTable = [[NSMutableArray alloc]init];
//Twitter new code
if (_accounts == nil) {
if (_accountStore == nil) {
_accountStore = [[ACAccountStore alloc] init];
}
ACAccountType *accountTypeTwitter =
[_accountStore
accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[_accountStore requestAccessToAccountsWithType:accountTypeTwitter
withCompletionHandler:^(BOOL granted, NSError *error) {
if(granted) {
dispatch_sync(dispatch_get_main_queue(), ^{
_accounts = [_accountStore
accountsWithAccountType:accountTypeTwitter];
[self sendRequest];
});
}
}];
}
}
-(void) sendRequest {
totalContent = [[NSMutableArray alloc]init];
_account = [_accounts objectAtIndex:0];
TWRequest *postRequest = [[TWRequest alloc]
initWithURL:
[NSURL URLWithString:#"https://api.twitter.com/1/statuses/user_timeline.json?screen_name=test&count=20"]
parameters:nil
requestMethod:TWRequestMethodGET];
av = [[proAlertView alloc]initWithTitle:nil message:#"Getting latest news..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
UIActivityIndicatorView * indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.frame = CGRectMake(120, 55, 35, 35);
[av addSubview:indicator];
[indicator startAnimating];
[av setBackgroundColor:[UIColor clearColor] withStrokeColor:[UIColor blackColor]];
[av show];
[postRequest setAccount:_account];
[postRequest performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse,
NSError *error) {
if ([urlResponse statusCode] == 200) {
NSError *jsonError = nil;
results = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];
dispatch_sync(dispatch_get_main_queue(), ^{
[av dismissAlert];
[self parseJson];
});
}
else {
[self showMessage];
}
}];
}
-(void)showMessage {
av = [[proAlertView alloc]initWithTitle:#"Connection Problem" message:#"Please confirm the device is connected to the Internet." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[av setBackgroundColor:[UIColor clearColor] withStrokeColor:[UIColor blackColor]];
[av show];
}
-(void)parseJson {
NSMutableArray * complete = [[NSMutableArray alloc]init];
for (NSDictionary * tweets in results)
{
NSString * status = [tweets objectForKey:#"text"];
NSString * date = [tweets objectForKey:#"created_at"];
NSDictionary * user = [tweets objectForKey:#"user"];
NSString * artistName = [user objectForKey:#"name"];
NSString * screenName = [user objectForKey:#"screen_name"];
NSString * artistImage = [user objectForKey:#"profile_image_url"];
cellContent = [NSArray arrayWithObjects:status,date,artistName,screenName,artistImage, nil];
[complete addObject:cellContent];
}
SecondViewController * tmpView = [[SecondViewController alloc]initWithNibName:#"SecondViewController_iPhone" bundle:nil];
tmpView.dataToDisplay = complete;
}
This class has been called like this:
- (void)viewDidLoad
{
[super viewDidLoad];
TwitterDataLoad * data = [[TwitterDataLoad alloc] init];
[data loadData];
NSArray * temp = dataToDisplay;
}
I know I am returning the value in a wrong way but i tried returning it through the loadData message itself to the view controller but it didn't work either so i was just trying this. Please don't care about that.
Thanks
Alright i figured out the problem with this.
dispatch_sync is doing what it is supposed to do the problem is with the other two statements under which dispatch_sync is been called (the other blocks )
[_accountStore requestAccessToAccountsWithType:accountTypeTwitter
withCompletionHandler:^(BOOL granted, NSError *error)
so this is an asynchronous call and dispatch sync gets called when the program control is back on the main queue as we have it defined like this : dispatch_sync(dispatch_get_main_queue())
and the method returns before the control is back on the main queue and hence the array doesn't gets any value.
So to solve this i wrote a block in my calling class which gets the return call once this data call is over. email me if you want the whole code #ghostsmitm#gmail.com
You should call reloadData on your UITableView once the data has been loaded. You can do this after calling loadData.

Resources