In CollectionView I am displaying datas from parse.com. Successfully retrieved. But unable to display in the cell. I am receiving error as Array outbound. I found out the mistake, parse is running as asynchronous. But, before parse end, collection view gets loaded. So I unable to display values in the cell. It is throwing an error. How to stop all the process until parse get loaded completely? Kindly guide me. MY CODING IS BELOW:
//VIEWCONTROLLER having collectionView
var myList : NSArray = NSArray()
let obj_par = parse_retrive()
obj_par.parse_DB() //DATAS GOING TO RETRIVE FROM PARSE
story_collection_view.reloadData() //RELOADING COLLECTIONVIEW
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
println("fifth")
if(collectionView == date_collection_view)
{
:
:
return cell
}
else
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("story_read", forIndexPath: indexPath) as story_reading_cell
cell.story_title.text = myList.objectAtIndex(indexPath.row) as? String //ERROR: ARRAY OUTBOUND OF INDEX
return cell
}
}
//PARSE_RETRIVE CLASS
func parse_DB() {
println("SECOND 10")
par_query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in
if (error != nil) {
NSLog("error " + error.localizedDescription)
}
else {
println("SECOND 13")
let sql_store_obj1 = sql_to_store() //THIRD CLASS
self.parse_obj_arr = NSArray(array: objects)
var j : Int = self.parse_obj_arr.count
for (var i : Int = 0; i < j; i++) {
self.par_object = self.parse_obj_arr.objectAtIndex(i) as PFObject
self.sto = self.par_object["story_title"] as String //STORY TITLE FROM PARSE
self.sto_con = self.par_object["story_content"] as String //STORY CONTENT FROM PARSE
self.sto_tit.append(self.sto) //STORING IN ARRAY VAR
self.sto_cont.append(self.sto_con) //STORING IN ARRAY VAR
} //FOR ENDING
sql_store_obj1.sto_title_arr = self.sto_tit
sql_store_obj1.sto_content_arr = self.sto_cont
sql_store_obj1.parse_to_sql()
}//ELSE ENDING
}) //PARSE QUERY ENDING
println("SECOND")
}
//THIRD CLASS
func parse_to_sql() {
let appDel : AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context : NSManagedObjectContext = appDel.managedObjectContext!
let ent = NSEntityDescription.entityForName("Sad", inManagedObjectContext: context)
var newStory = story_sad_managed(entity: ent!, insertIntoManagedObjectContext: context)
newStory.story_title = sto_title_arr
newStory.story_content = sto_content_arr
let request = NSFetchRequest(entityName: "STORY")
request.predicate = NSPredicate(format: "story_title = %@", sto_title_arr)
result = context.executeFetchRequest(request, error: nil)!
let sto_page_obj = story_page()
sto_page_obj.myList = result //1st CLASS ARRAY
}
NOTE: All code is in Objective-C, but the translation for this particular code should be trivial. If someone wants to edit my post to include the Swift code, please feel free, but please leave the Objective-C in the post.
What I do (for UICollectionView
or UITableView
) is create a property, normally called isLoading
like this:
@property (assign, nonatomic) BOOL isLoading;
I normally initialize it like this:
- (void)viewDidLoad {
[super viewDidLoad];
// This could also be done in viewWillAppear/viewDidAppear
// based on your needs/desires
self.isLoading = NO;
[self loadData];
}
- (void)loadData {
if (self.isLoading == YES) {
// Just in case a "loadData" call is made while one is pending...
return;
}
// Prevent this method from firing again until
// data loading is done; prevent UICollectionView
// from attempting to display missing data
self.isLoading = YES;
// Do whatever you need to do...
// Clean up and prepare for UICollectionView
self.isLoading = NO;
[self.collectionView reloadData];
}
Now, the real secret is, of course, that you have to implement logic in your UICollectionViewDataSource
methods to display data conditionally based upon self.isLoading
, like this:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.isLoading == YES) {
// You might want to return 0 or 1,
// depending on whether you have a "loading"
// placeholder cell. Assume you do:
return 1;
} else {
// Return whatever is the correct number here
}
}
Generally, that's all I need to get my screen to delay loading the UICollectionView
until the Parse query has returned correctly.
When I have multiple queries that will run concurrently, all of which should return before I consider data loading to be complete, then I create a BOOL
property for each of them, setting the flags as appropriate, and I funnel all query returns through a checkIfDone
method. Something like this:
@property (assign, nonatomic) BOOL data1Loaded;
@property (assign, nonatomic) BOOL data2Loaded;
@property (assign, nonatomic) BOOL data3Loaded;
@property (assign, nonatomic) BOOL data4Loaded;
- (void)loadData {
if (self.isLoading == YES) {
return;
}
self.isLoading = YES;
self.data1Loaded = NO;
self.data2Loaded = NO;
self.data3Loaded = NO;
self.data4Loaded = NO;
// Call each of the separate data loading methods...
[self loadData1];
[self loadData2];
[self loadData3];
[self loadData4];
// Notice that I don't do any reloadData calls here...
}
- (void)loadData1 {
PFQuery *query = // Some query creation...
[query findObjectsInBackgroundWithBlock:
^(NSArray *objects, NSError *error) {
if (error != nil) {
// Handle "got error"
} else {
// Handle "got good data"
}
// Either way, #1 is done, so:
self.data1Loaded = YES;
// This pattern checks for completion and
// runs the completion code only when all
// 4 (in this case) items/queries have returned
[self checkIfDone];
}
];
}
- (void)checkIfDone {
if (self.data1Loaded == YES &&
self.data2Loaded == YES &&
self.data3Loaded == YES &&
self.data4Loaded == YES)
{
// Clean up and prepare for UICollectionView
self.isLoading = NO;
[self.collectionView reloadData];
}
}
Caveat: This assumes that any subsequent calls to
loadData
will occur in the background and that any subsequent calls to[collectionView reloadData]
will only take place at the end of your query calls. If anything else might callreloadData
in the meantime, you will need more advanced logic to ensure that the correct data is loaded correctly.
Side Note: When doing something like this, don't forget to show the user an indication that work is progressing. I like to use the open source
MBProgressHUD
. It's available here on GitHub. I have found it invaluable for doing exactly what you're talking about doing.
来源:https://stackoverflow.com/questions/28217277/in-swift-how-to-stop-all-the-process-until-datas-retrieved-from-parse-com-in-ui