How to get Parse.com object count in class - ios

I want to get the object count from 5 classes in Parse.com (to check if all objects were fetched successfully).
Because I'm using findObjectsInBackgroundWithBlock: sometimes not all the objects are fetched before I'm using it, that's why I want to check.
How can I do that?

Update 2: just noticed you were asking about iOS. its basically the same principle, use fetchAllIfNeeded like so:
https://parse.com/docs/ios/api/Categories/PFObject(Synchronous).html#/c:objc(cs)PFObject(cm)fetchAllIfNeeded:
Update: a better way than the naive one (below) would probably be using fetchAllIfNeededInBackground:
ArrayList<ParseObject> objectsToFetch = new ArrayList<>();
objectsToFetch.add(object1);
objectsToFetch.add(object2);
objectsToFetch.add(object3);
ParseObject.fetchAllIfNeededInBackground(objectsToFetch, new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
//all are fetched, do stuff
}
});
My native way of doing this is adding an outer boolean array where each boolean is responsible for one of the classes.
When a findObjectsInBackgroundWithBlock's 'done' function runs, I set that boolean to "true" and run a function that checks whether all array is true, if so -> all classes have been fetched and I can continue.
example from my code:
boolean[] itemFetched;
protected void getAllClassesAndDoStuffWithThem() {
itemFetched= new boolean[NUM_OF_CLASSES];
for (int i=0;i<NUM_OF_CLASSES;i++){
final int finalI = i;
itemFetched[i] = false;
parseObjectArray[i].fetchIfNeededInBackground(new GetCallback<ParseObject>() {
#Override
public void done(ParseObject object, ParseException e) {
itemFetched[finalI] = true;
finishInitIfPossible();
}
});
}
}
private void finishInitIfPossible() {
for (int i=0;i<NUM_OF_CLASSES;i++){
if (!itemFetched[i])
return;
}
//all classes fetched
finishInit();
}
private void finishInit() {
//do stuff with all 5 classes
}

Related

Is it possible to add an item to a List contained in a Stream in Dart?

Problem
I have a Stream<List> which is being listened to in several classes and I need all the classes to receive the updated stream once a value is added to the list in the Stream.
What I have tried
void main() {
StreamedList<String> dataStream = StreamedList();
dataStream.data.listen((list) => print(list));
dataStream.updateList(['Apple', 'Orange']);
dataStream.addToList('Mango'); // This is what I want to do
}
This is the code for StreamList class
class StreamedList<T> {
StreamController<List<T>> _controller = StreamController.broadcast();
Stream<List<T>> get data => _controller.stream;
void updateList(List<T> list) {
_controller.sink.add(list);
}
void addToList(T value) {
// Is it possible to do this?
// List<T> dataList = await _controller.data;
// dataList.add(value);
// updateList(dataList);
}
void dispose() {
_controller.close();
}
}
I have tried different APIs from the dart:async library including Stream.first, etc. which return a Future<List<T>>. But the problem is that this Future resolves only after something is added to the Stream later (eg. by calling the StreamedList.updateList function).
Question
How do I add a single value to the List inside the Stream?
You are misunderstanding what a Stream does. It doesn't "contain" data. It merely accepts data on one end (the sink) and propagates it out the other end (the stream), and any listeners gain access to the streamed object. Trying to "insert an item in a list within the stream" doesn't make any conceptual sense.
If you want to push a list with an additional item, take the old list, append the item to it, then re-add the list to the stream.
class StreamedList<T> {
StreamController<List<T>> _controller = StreamController.broadcast();
Stream<List<T>> get data => _controller.stream;
List<T> _list = [];
void updateList(List<T> list) {
_list = list;
_dispatch();
}
void addToList(T value) {
_list.add(value);
_dispatch();
}
void _dispatch() {
controller.sink.add(_list);
}
void dispose() {
_list = null;
_controller.close();
}
}
If you wanted to be doubly safe, you could recreate the list after every addToList, since if a listener captured the list elsewhere and modified its contents, that would affect _list as well.
void addToList(T value) {
_list = [..._list, value];
_dispatch();
}

Chaining InputOperations in Rhino-Etl

I've just recently started using Rhino-Etl for very simple ETL processes and have had great success with it. I have a slightly more complicated scenario to address now and I didn't find the ConventionInputCommandOperation behaving the way I expected.
I've done up a very simplified example of what I'm trying to do. Basically I have two systems involved and I don't know what I want to get from system 2 until I first query system 1. I thought registering an InputOperation immediately after another InputOperation would behave like a loop. So that each row in operation 1 would be fed to operation 2. The below code fails with "Failed to execute operation DetailReader: Must declare the scalar variable #PlanetAbbrv." So my question is how are you meant to handle situations where the input operation is dependent a previous input operation?
Thanks,
Brian
using System;
using Rhino.Etl.Core;
using Rhino.Etl.Core.ConventionOperations;
namespace ETLTest
{
class Program
{
static void Main()
{
new MainProcess().Execute();
Console.ReadLine();
}
}
public class MainProcess : EtlProcess
{
protected override void Initialize()
{
Register(new MainReader());
Register(new DetailReader());
}
protected override void PostProcessing()
{
foreach (var exception in GetAllErrors())
{
throw exception;
}
}
}
public class MainReader : ConventionInputCommandOperation
{
public MainReader() : base("Galactic1")
{
Command = #"select * from Planet";
}
}
public class DetailReader : ConventionInputCommandOperation
{
public DetailReader() : base("Galactic2")
{
Command = #"select * from Delivery where DeliveryPlanetAbbrv = #PlanetAbbrv";
}
}
}
You'll need to have your DetailReader select all rows (take out the where operation).
Then use a JoinOperation to match the details to the main information.
Register(new JoinPlanets()
.Right(new MainReader())
.Left(new DetailReader()));
public class JoinPlanets: JoinOperation
{
protected override Row MergeRows(Row leftRow, Row rightRow)
{
Row row = leftRow.Clone();
foreach (var column in leftRow.Columns)
row[column] = leftRow[column];
return row;
}
protected override void SetupJoinConditions()
{
FullOuterJoin.Left("PlanetAbbrv")
.Right("DeliveryPlanetAbbrv");
}
}

SQLite Serialized Mode

I have an Xamarin Android project and was using mono.data.sqlite and had problems with multithreading, so I tried the Zumero component. I'm still having problems. I'm trying to set serialized mode as with the flag SQLITE_CONFIG_SERIALIZED in http://www.sqlite.org/threadsafe.html. I'm still getting random crashes. Can I set the serialized flag with Zumero? Any other suggestions other than recompiling SQLite from the source?
Thanks,
Brian
I used to have this problem. And despite conflicting recommendations here's how I stopped getting the exceptions:
Share a static instance of SQLiteConnection between all threads. This is safe to do as SQLite connection is only a file pointer it's not like a traditional data connection.
Wrapped all my SQLite queries/inserts/updates in a mutex with the statix instance of my SQLiteConnection as the lock. I've been advised that I shouldn't need to do this when using serialized mode however my experience with it begs to differ.
lock(myStaticConnection) {
myStaticConnection.Query<Employee>("....");
}
As a backup I also use some added retry logic to encapsulate every query. Not sure if SQLite does this on its own (I've seen reference to busytimeout and people claiming it is now gone?). Something like this:
public static List<T> Query<T> (string query, params object[] args) where T : new()
{
return Retry.DoWithLock (() => {
return Data.connection.Query<T> (query, args);
}, Data.connection, 0);
}
public static T DoWithLock<T>(
Func<T> action,
object lockable,
long retryIntervalTicks = defaultRetryIntervalTicks,
int retryCount = defaultRetryCount)
{
return Do (() => {
lock (lockable) {
return action();
}
});
}
public static T Do<T>(
Func<T> action,
long retryIntervalTicks = defaultRetryIntervalTicks,
int retryCount = defaultRetryCount)
{
var exceptions = new List<Exception> ();
for (int retry = 0; retry < retryCount; retry++) {
try{
return action();
} catch (Exception ex) {
exceptions.Add (ex);
ManualSleepEvent (new TimeSpan(retryIntervalTicks));
}
}
throw new AggregateException (exceptions);
}

How can I get cursor update notifications without a CursorAdapter?

I'm writing a Fragment that uses a loader to get a Cursor containing data about locations of various things on a map. I've inherited code to sort these locations by distance from the device, or from a search location; distance metrics aren't something that's particularly easy to implement in SQL, so rather than use a CursorAdapter (as elsewhere) I'm loading the data once from the Cursor and then sorting it afterwards.
I have just one problem: when the web service returns a new set of locations (for example, on first load), the list isn't updating. I've registered a ContentObserver on the Cursor and it is being hit when I call notifyChange(...) in the ContentProvider; it's just that the Cursor I've stored from the original load still has a count of zero.
The callbacks and the ContentObserver look like this:
private LoaderCallbacks<Cursor> mCallbacks = new LoaderCallbacks<Cursor>() {
public void onLoaderReset(Loader<Cursor> loader) {
mLoaderCreated = false;
mCursor.unregisterContentObserver(mObserver);
mCursor = null;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if(cursor!=mCursor) {
if(mCursor!=null)
mCursor.unregisterContentObserver(mObserver);
cursor.registerContentObserver(mObserver);
mCursor = cursor;
if(cursor.isClosed()) {
getLoaderManager().restartLoader(mFragmentId, null, mCallbacks);
return;
}
}
mDataModel.populate(cursor);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
mLoaderCreated = true;
triggerServicesFeed();
CursorLoader cursorLoader = null;
if(id == mFragmentId) {
cursorLoader = new CursorLoader(getActivity(),
FerrariVertuContentProvider.SERVICES_URI,
null, null, null,null);
}
return cursorLoader;
}
};
private ContentObserver mObserver = new ContentObserver(null) {
public void onChange(boolean selfChange, android.net.Uri uri) {
onChange(selfChange);
};
public void onChange(boolean selfChange) {
if(mCursor.isClosed()) {
mCursor.unregisterContentObserver(this);
mCursor = null;
} else {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
//mCursor still reports zero on first run
mDataModel.populate(mCursor);
}
});
}
};
};
I know CursorAdapter just updates when the Cursor updates, and the fact that I'm getting update events when I'd expect to makes me think this stage of the process, at least, is working. How do I either get mCursor to give me the new data, or get a fresh Cursor representing the new data?

db4o Tranparent Persistence doesn't store later objects in my own ActivatableCollection<T>

I'm rolling my own ActivatableCollection<T> for db4o but cribbing heavily from the builtin ActivatableList<T> implementation. I'm running into the problem where transparent persistence doesn't seem to be working correctly. In the test code below:
[Fact]
void CanStoreActivatableCollection()
{
var planets = new ActivatableCollection<Planet>();
var pagingMemoryStorage = new PagingMemoryStorage();
var config = Db4oEmbedded.NewConfiguration();
config.Common.Add(new TransparentActivationSupport());
config.Common.Add(new TransparentPersistenceSupport());
config.File.Storage = pagingMemoryStorage;
var objectContainer = Db4oEmbedded.OpenFile(config, "Memory.yap");
planets.Add(new Planet("Mercury"));
objectContainer.Store(planets);
planets.Add(new Planet("Venus"));
planets.Add(new Planet("Earth"));
objectContainer.Commit();
objectContainer.Close();
config = Db4oEmbedded.NewConfiguration();
config.Common.Add(new TransparentActivationSupport());
config.Common.Add(new TransparentPersistenceSupport());
config.File.Storage = pagingMemoryStorage;
objectContainer = Db4oEmbedded.OpenFile(config, "Memory.yap");
planets = objectContainer.Query<ActivatableCollection<Planet>>().FirstOrDefault();
Assert.NotNull(planets);
Assert.Equal(3, planets.Count);
objectContainer.Close();
}
The planet "Mercury" is stored, but not "Venus" and "Earth". If I change from ActivatableCollection to ActivatableList, then all 3 planets are stored.
What am I missing? My ActivatableCollection is just minimal implementation of ActivatableList as best as I can tell.
Below is my implementation of ActivatableCollection:
public class ActivatableCollection<T>
: ICollection<T>
, IActivatable
, INotifyCollectionChanged
{
List<T> _list;
List<T> List
{
get
{
if (_list == null)
_list = new List<T>();
return _list;
}
}
public ActivatableCollection()
{
}
public int Count
{
get
{
ActivateForRead();
return List.Count;
}
}
public bool IsReadOnly
{
get
{
ActivateForRead();
return ((IList) List).IsReadOnly;
}
}
public void Add(T t)
{
ActivateForWrite();
List.Add(t);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, t));
}
public void Clear()
{
ActivateForWrite();
List.Clear();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public bool Contains(T t)
{
ActivateForRead();
return List.Contains(t);
}
public void CopyTo(T[] array, int index)
{
ActivateForRead();
List.CopyTo(array, index);
}
public IEnumerator<T> GetEnumerator()
{
ActivateForRead();
return List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public bool Remove(T t)
{
ActivateForWrite();
bool removed = List.Remove(t);
if (removed)
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, t));
return removed;
}
[Transient]
private IActivator _activator;
public virtual void Bind(IActivator activator)
{
if (_activator == activator)
return;
if (activator != null && _activator != null)
throw new InvalidOperationException();
_activator = activator;
}
public virtual void Activate(ActivationPurpose purpose)
{
if (_activator == null)
return;
_activator.Activate(purpose);
}
protected virtual void ActivateForRead()
{
Activate(ActivationPurpose.Read);
}
protected virtual void ActivateForWrite()
{
Activate(ActivationPurpose.Write);
}
[Transient]
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
CollectionChanged(this, e);
}
}
I've also tried copying the code from GenericTypeHandlerPredicate and registering my ActivatableCollection to use the GenericCollectionTypeHandler. That results in a crash in GenericTypeFor() throwing an InvalidOperationException() when "Mercury" is being stored.
Just want to mention my answers from the db4o forums also here, for people with a similar problem:
First part of the issue:
From db4o's point of view nothing has changed in the 'ActivatableCollection' object and therefore no changes are stored. This is what is happening:
When you add the items, the ActivatableCollection is marked as changed.
When you commit the changes are stored. However the ' ActivatableCollection' holds the reference to the same object. db4o only stores the changes in the ActivatableCollection-object, which is the reference to the List. Since it is the same, no actual change is stored.
The List of the ActivatableCollection is never updated, because it wasn't marked as 'changed'
So the transparent activation doesn't see the changes in the list. You can fix your issue simply by using an ActivatableList in you're ActivatableCollection implementation. Just change the List with a IList interface and instantiate a ActivatableList instead of an List.
The second part of the issue: Why doesn't it work even when registering the GenericCollectionTypeHandler for this type? Here we hit a implementation detail. The GenericCollectionTypeHandler has an internal list of supported types, which doesn't include the self made 'ActivatableCollection'. GenericCollectionTypeHandler is not really part of the public API and intendet for internal use only.
Workaround / Fix
Just use an ActivatableList<T> instead of a List<T>. then everything works fine.

Resources