Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
VirtualView (share code, from novice)
-
Still working on the VirtualView :) even, if no one ever uses it other than me, I am still having fun and learning a lot.
Yes, sorry the gist ID is a new one again. @omz, it would be great if your built in gist export could update a gist.
Anyway, it's getting a little messy now as I am trying to keep it all in one .py file.I have added a type of navigator to move through the list in percent increments, some new demo cell row styles and a start of a table (table header and columns ). None of this is real pretty, I will keep working on it. But gives the idea.
Also fixed some fundamental flaws manipulating the scrollview. Sometimes I was using the bounds of the scrollview, other times the bounds of the parent view. All was good as long as the scrollview took up the entire view :( I found out the hard way as soon as I tried to add another view :) this has been fixed
Also added a Stress class. All it does is scroll the view in the VirtualView programmatically. I ran it 7 hours, with it creating and destroying 4.8 million cells. Only one warning, your iPad hardly gets a charge. While that was running I got about 6% in 7 hours. Less than an a percent an hour ;)
Anyway, if you are self inclined to look at it, happy for any scathing comments or improvement suggestions.
-
don't use
__del__
! This is not the use case for it. You get lucky because you don't have any reference cycles, but i think you are developing a bad habit.remove it and run your stress case to verify. for that matter, stress does not seem to need
__del__
, or the self delete... just return when obj is not on_screen. -
@JonB, you could submit a pull request to https://github.com/Phuket2/Pythonista-Code/blob/master/VirtualView.py to make your approach clear.
-
Ok, I wil get rid of the del. It just seems such a shame. It seems the way it should be done. To me anyway.
When I onscreen is false, I say self del, is that valid? Or is that also a bad practice? -
@JonB, oh I again didn't read your response correctly. You already say, I don't need the self del. but ok, I will read more on python memory best practices. It just drives me crazy. Even though it's been years since I was coding, this idea of being explict sticks with me. I hate this idea that it will probably get cleaned up.
I know this is not the place for this discussion. I think I might have a better/different view if I was coding on a desktop as well. But I don't. Only doing Python on the iPad.
Maybe my other code contradicts my wanting to be explicit and correct statement, but my goal is to be a good programmer again one day. Not about been flashy, just good solid code that works and is readable and economical. I will get there. Will be some extra grey hairs though :)
But I do thank you and all the other guys here for your help. It's invaluable. -
I'm pretty sure
del self
is totally unnecessary, and probably is not doing what you think. An object cannot be deleted until the last reference is gone.class Depressed(object): def suicide(self): print 'goodbye cruel world' del self def attempt_suicide(self): self.suicide() print self, 'finds a reason to live' Depressed().attempt_suicide()
You will see that
del self
doesn't actually do anything, except delete the local version of self insidesuicide
-- the object still exists because it was referenced inside.Since you didn't create any references in main to your Stress() object, it will magically go away once there are no references to it, and that memory can be used by other python objects.
Here's a simple example showing that having a
__del__
method can get you into trouble.class A(object): def __del__(self): print 'del called on ', self a=A() b=A() a.b=b b.a=a del(a) del(b) import gc gc.collect() gc.garbage
You will see in this case, we created a reference cycle, but because of the
__del__
method, the gc module won't garbage collect (because it doesn't know whether to call del on a or b first). So your good intentions of having some cleanup actually prevent the objects from getting cleaned up! Contrast that with this example:class B(object): def blah(self): pass a=B() b=B() a.b=b b.a=a del a del b gc.collect() gc.garbage
Here we create the same reference cycle, but python's gc module is smart enough to handle it, and there is no garbage.
That's the reason you shouldn't use
__del__
unless there really is a resource you are cleaning up, like needing to close a file handle or socket. But even then, note that there is no guarantee that__del__
will be called when you caldel
-- if it was referenced by another variable which was part of a reference cycle, the reference cycle does not get resolved until gc runs collect (which happens periodically, or you can manually do it)a=A() b=B() c=B() b.c=c c.b=b c.a=a del(a) del(b) del(c) #note a.__del__ still has not run! gc.collect() # NOW a.__del__ ran.
In summary: if you are just trying to manage memory... the best way is by making sure you don't store references to objects you want to go away, and don't have
__del__
on any object which could become involved in a reference cycle. -
@JonB , again, thanks very much. I realise this is out of the scope of this forum. I think I am starting to get a grip on it now (we'll sort of). My idea of your summary, is you should code in a way that objects will fall out of scope when expected , and then the gc will clean up when appropriately unless you explicitly force it with a call to gc.collect, which under normally circumstances you should not need to do.
Also have to understand Phyons concept of object sharing / ref count.The del issue you point out, I think I have been having the same problem with releasing resources when it comes to ui.Views. If an action/method is set for an object in the view, the view and its resources are not being released. Maybe not 100% the same, but almost. I think under normal conditions, this would be be noticed. But for example, if you say have 10 views you want to display inside a window/view. And because of memory concerns you decide not to hide and show them, but load them and remove them. From what I can see, this will work fine. But, if any of the views say has a button that the action is defined, the view will not get unloaded. That method/function reference appears to stop the gc from releasing it. I am pretty sure I am right about this. It's just worth noting. If I am wrong, I am happy with that, but for sure, when creating thousands of views that has an object like a button with a callback method/function it will crash
-
right on, though one correction -- if you not only design things to fall out of scope but also to have no lngering strong references in other objects, then when it does fall out of scope gc does not get involved, at all! once the ref count goes to zero, memory is freed. gc gets involved to unwind circular references (figuring out that the only places an object is referenced is from other deleted objects).
In a ui application, i would think it is important to remove_subview, and if your custom class refers to other objects, set those to None when you remove your object, for instance buttons that link back to a custom class through the action attribute.
-
@JonB , I am starting to understand. But it's not self evident. A lot of gotchas. But in a normal app, you will not see the problem as the memory leaked will be minimal, but it can easily be leaked. I am really not trying to split hairs. I just think your app should not leak 1 byte of memory. It's about understanding your environment. Which, at the moment I don't, but I am trying to.
-
@JonB , oh my next idea for a VirtualCell is going to be funny. I want to make a cell that is waiting for data from a URL. Will have to do many things I guess. It's actually beyond my experience, but I will try anyway. I have some ideas, but I do not the coding experience to make it happen.
My thoughts are, to call a function to create a cell on a thread. The cell will have some built in animation/greyed out image indicating its loading. If the cell is out of the buffer ( scrolled out of range), I will have to terminate all tasks relating to gathering the data as well as releasing the resources. When and if it completes, I think I need to know that also. Also because scrolling can be fast, I think I need to have some delay before I even attempt to get the web resources. Will be just an exercise for me. But a very difficult one -
Check out my dropdown view.
https://github.com/jsbain/uicomponents/blob/master/dropdown.py
I apologize for the uncommented code... but basically, i have a thread that populates a tableview, while still allowing the user to selct or cancel before the list is fully populated. This was mainly for gitview, where I walk the entire directory structure looking for repo folders.so what you suggest is indeed possible. consider using an ui.ActivityIndicator inside the cell, as a nice way to show it is loading. IIRC, you might need to use
on_main_thread
to update things (i think that is why i used animate) -
@JonB , thanks. I have the code. I will look through it and try to understand. I will create a little test app to see if I can get the hang of how the threads are working also. I have done nothing with threading etc using the wrappers in ui. Also almost never used them in c. So it will be interesting to see what mess I can get myself into now :)
-
VirtualView with Threaded Cells
@JonB, I had a stab at creating threaded cells. What I was happy about is that I didn't need to change anything in the VirtualView class. I made a new Class called ThreadedCell. Just to seperate it. Until now, the mechanism appears to work. But I think I am supposed to use join. I haven't got my head around that yet. Anyway, it appears to behaving nicely at the moment. But I am really just guessing. I have to read a lot more. Also one big issue is I am not getting any data externally yet. I am just using time.sleep(random.random()) a few times to simulate the data fetching. When I try to start to add something like requests in there, I might get a shock :)
A different idea from your example as I am putting every cell on its own thread rather than trying to populate the table async with a single thread.
Anyway, trying....
Maybe, it's a big fail again! -
@JonB, Oh, if you pass delay = .01 to Stress, and manually scroll it while it's doing its thing, does not seem to miss a heart beat. Well at the moment
-
@JonB, I put in the ActivityIndicator as you suggested. Won't put another gist for that, but works great. One thing to note though, the documentation eludes to 3 styles of indicators. But there are many....
-
Fingers crossed this works. The repo that is.
@ccc, @JonB , ok I finally got a repo up. But, I have been changing so much. A lot not pretty, but I have been trying, also many things not completed. I think you guys will not agree with the multiple inheritance ( I just think, not sure). But, the threading and the memory/resource control seems pretty good, to me! It feels like I have done something wrong, because it seems to easy. I haven't done any locks, on_main_thread etc... However, it seems very solid to me....but, Wikipedia is not large enough for what I don't know.