Can I avoid JViewport revalidation every time setViewPosition() is called? - jscrollpane

I was debugging a problem with a custom scrolling view using a subclass of JViewport. I was printing some information from the layoutContainer() method in my custom LayoutManager, and saw that it was being called continuously, without any resizing to trigger it. I looked at the source and it appeared as though JViewport.setViewPosition() revalidates on each call. I thought that can't be. So I went back to another project using a standard JScrollPane, and added this code:
myScrollPane.setLayout(new ScrollPaneLayout() {
#Override
public void layoutContainer(Container parent) {
System.out.println("Layout ScrollPane");
super.layoutContainer(parent);
}
});
which proved that the standard version suffers from this same problem. Is there a robust and accepted way around this? I'm using several instances of my JViewport subclass to display a waveform and other things scrolling in real time using JViewport.setViewPosition() and laying out the container (exactly the same each time) every 10 milliseconds is a big inefficiency. I can subclass JViewport and override this, but understanding why it was deemed necessary to revalidate simply for a change in the view position would help me to avoid making an new problem. Currently I'm puzzled as to why this is necessary.
So the corollary question is "why is JViewport.setViewPosition()" causing a revalidation?".

Related

Is there a reliable way of overriding CellClass in classes derived from NSControl?

This question seems to have been asked several times, but I have yet to find an definitive answer. I'm totally aware of the fact that NSCell is "being gradually phased out". This is great (and long overdue!), but it doesn't help in the here and now. Suppose I want to create a subclass of NSImageView which (e.g.) clips an image with an arbitraily shaped mask. I might define it like this:
class MaskedImageView : NSImageView {
public override class var cellClass: AnyClass? {
get { MaskedImageCell.self }
set {}
}
MaskedImageCell, of course, inherits from NSImageCell. This code compiles just fine under Swift 5.x, but the cell class is never changed. Adding the statement super.cellClass = newValue to the above property setter likewise makes no difference. (In fact, this isn't how the underlying AppKit machinery establishes the cell class. If I add a print statement inside the property getter, I can see that AppKit is interrogating the cell class, as I'd expect, but it never uses it.)
Like I said, I'm aware that NSCell is on the way out. But there are surely multiple use cases where it would be useful to change the cellclass to add specifics required by a particular application. If this isn't possible NOW, then is one supposed to try and replicate the entire functionality of (eg) NSImageCell. I surely wouldn't want to do that!
All constructive comments gratefully received. And please do bear in mind that I'm not actually interested in adding weird-shaped masks to NSImageViews. 😄 What I'm after is a definitive solution to the problem of introducing one's own cell class into the mix. We were told 7 years ago that NSCell was being deprecated, but while it's still with us, we should have a mechanism for introducing custom cell classes.

Pros/cons of implementing a particular set of delegate methods versus not implementing them and the effects of implementing one but not another?

In regards to UITableView & UICollectionView & their respective protocols, UITableViewDataSource & UITableViewDelegate + UICollectionViewDelegate & UICollectionViewDataSource -- are there any pros and cons to implementing one method, but not the other or a particular set of methods and not the rest of the methods or a unique combination of specific methods?
For example, if I am to implement heightForFooter but not viewForFooter - what happens or can happen? Does this negative impact performance or the scroll of the table view?
Is there a guide which shows that which if any methods are implemented, others should be combined and dually implemented alongside them?
Re: correctness
Is there a guide which shows that which if any methods are implemented, others should be combined and dually implemented alongside them?
Not from what I've seen, though sometimes the documentation mentions it. E.g. from the docs of NSTableViewDataSource:
If you’re not using Cocoa bindings to provide data to the table view, the following methods are required:
numberOfRows(in:)
tableView(_:objectValueFor:row:)
tableView(_:setObjectValue:for:row:) (cell-based tables only)
In general, if a method is optional, but required from the context, then there will be a runtime error telling you to implment it, e.g.:
Illegal NSTableView data source (Foo). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
Either that, or stuff will silently fail (e.g. if you don't implement NSTableViewDelegate.tableView(_:viewFor:row:), no drawing will happen, and all your cells will just be blank views.
Re: performance
There shouldn't be any real performance difference with not implementing optional methods.
Each of these methods is likely called as if you had this in Swift (most of these frameworks are still implemented in Objective C):
let result: Result? = yourTarget.someMethod?(someArg)
which is really just shorthand for:
let result: Result? = yourTarget.responds(to: #selector(YourTargetsClass.someMethod))
? target.method(someArg)
: nil
That is, it's one dynamic method lookup to check if your object responds to the message, and one dynamic message send to actually invoke the method (for the case where it does respond).
There's a teeny tiny optimization that one could squeeze out here: if your method implementation is empty, then you're better off not having it at all. That will prevent a needless message send. Though it's obviously not something to worry about until you're sure it's a hotspot in a profiler.
Of course, nothing stops a library author from writing:
if yourObject.responds(to: #selector(someMessage)) {
doSomethingVeryExpensiveForNoGoodReason()
}
... but that's unlikely.

Destroy UIView in init if condition isn't met

I'm trying to make a custom alert view that checks to see if a condition is true, and if so it builds itself and attaches itself to the window. However, if this condition is not true, I just want the view to deallocate itself, preferably in the init method. What is the best way to accomplish this?
Well it is better to follow SOLID principles in coding.
Singularity is an important thing.One function is supposed to do a single thing not many dependencies.
So Keep the view just to show the custom alert.And the check for showing must be done outside such that
//Please note this is the algorithm not the exact code in Obj-C.
if(condition==True)
{
//Display customView
}
else
{
//Do nothing
}

How do I "connect" a table view to a view controller

Alright, I know this is a vague conceptual question, but I really need help here. Thanks in advance if you decide to take the time to read this. I would never even consider writing this much except this is such a great forum with so many helpful people I thought this would be the best place to ask.
This is all related to the question here (you don't have to look at it - I explain everything below): Pass parameter when initializing table
I've been working for days on the same problem, but I'm realizing there must be something big I'm missing. I've googled and googled and I even bought (and about 50% read) two Obj-C books a few days ago, but I'm still grasping at something that seems like it should be incredibly easy. I'm obviously pretty new to OOP, but I have mediocre skills in HTML, perl, sql, python as well as some of the ancient stuff like pascal and basic. I'm a n00b, but not a moron (well, actually this experience is changing my mind a bit).
Anyway, my end goal here is to simply create an app with 8 "normal" buttons on the first view (level 1), each doing basically does the same thing - which is to show a simple table view (level 2) with data in cells that can be clicked to continue to drill down to details (level 3). Very basic and straightforward concept. The only difference between the 8 possible level 2's is the data that will be shown. I've already constructed sql queries that work just as I want for each button.
So, here's where I stand: I have a perfectly working app that does everything from level 2 down exactly as I expect - the queries work, the tables are beautiful - so that's great.
Also, I have another nav-based app that launches on "level 1" and shows me 8 buttons (I hide the nav bar on level 1). If I click any of the buttons on level 1, the level 2 view (which is a nav bar + a table) slides into view exactly like I want. The problem is the table is just blank. No matter what I do, I can't get the level 2 in the second app to show me the data, even though I can show all of that data in the first app perfectly. For the life of me, I can't figure out how to "link" level 1 with level 2.
Hopefully you can understand this gap I'm trying to bridge. Since there are 8 possibilities for level 2 (with only very slight differences in sql queries on the same sql table), I initially tried coming up with a way of "passing" an integer to the level 2 view (in the first app) and then selecting the sql query based on what was passed (see the link above for that fiasco). Once I got that working, I planned to figure out how to make the buttons do the "passing" later. However, after about 16 hours screwing with that, I just gave up and decided to make 8 different table view controllers, all with nearly identical code except the query. That way, if I could just get a SINGLE button on level 1 to simply push to just ONE of the level 2's with NO parameters I would be a horrible but successful programmer.
Unfortunately, even that hasn't worked out for me. I have tried every possible control-drag and window/view/table combination I can think of in Interface Builder, but no matter what I try, the data never loads into the table view, even though it works great in my first app. I have gone through every line of code - they are the same except something has to "call" or "launch" the level 2 part and I'm just not getting it.
So, I'm going to break with convention/expectations here and not post any code in my question. I just want to know - how can this possibly be so difficult?? I am very analytically minded and I catch on quickly, but I have to say I have never been so humbled by a technical challenge in my life.
Can anyone explain to me, at a conceptual level, what I need to be doing here or what I'm missing? Even if you give me a link to something to read I would appreciate it very much. I have watched tens of hours of tutorials on youtube, but I'm always up for more.
Of course I'm willing to share my code, but there is so much of it and I'm so new at this I really don't know where the relevant parts are. Plus, I actually want to learn how all of this works so I can help others. If there is such a thing as PM on here I'll email it to you if you're willing to take a look. Once I get it working, I will post the code here. I have to believe there are other people looking for the same kind of thing as I am. However, more importantly, I just want to know, from a high level, what is the correct way to approach my problem? If you look at my link you can see what I've been trying (which was to pass an integer to the method that populates the table), but as I said, I basically gave up on that because I wasn't getting anywhere. People are trying to help me, but I'm an idiot.
Thanks for bearing with my agonizingly long message. If you made it this far and have some suggestions for me I'm all ears. I'll be honest, though - if you tell me I should just scrap the whole thing and use core data I'll cry. I really don't think I have the time to figure out a whole different way of managing data. As I said, I'm pretty happy with the database and the query parts of my app - it's just managing the freaking views and passing data between them that is killing me!
Any help is appreciated - thank you all so much.
If I understand your question correctly, you are asking how to initialize a view controller and pass in some data to alter its behavior. The key concept here to understand is how objects are initialized in Objective-C. One of the most common questions that developers who are new to iOS have is:
How can I pass data between my views?
Yes, eight different links there. (Okay, that eighth link is a little bit off topic, but it's close enough.) There are several ways of doing this and I'll go through them briefly. I'll also describe custom initializers, which are a relevant point as well.
Let's pretend we were building a catalog application which shows a bunch of products in various categories. Imagine that our app opens to a list of products, much like the Apple Store App. Say that when the user taps on a product we want to show a product page.
You can set properties on the "next" view controller. - Simply, we can create a UIViewController subclass and set the productID property (which we made up). Let's call our new UIViewController a ProductPageViewController. Here's how this would look:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
//Create a ProductPageViewController
ProductPageViewController *ppvc = [[ProductPageViewController alloc] initWithNibName:#"ProductPageViewController" bundle:nil];
//set the property on our ProductPageViewController
[ppvc setProductID:42];
//We would usually present the PPVC here.
//After presenting, remember to release the view controller
}
In the first line, we create the product view controller. We call alloc, then init. (The functions are wrapped - that is, we call init directly on the result of the alloc method.)
Then, we set a property of our view. The view can now be configured in viewWillAppear and all is well.
You can share the data through a persistent store. - This method works a little differently. The view controllers don't communicate at all, except for the first one presenting a second one. Whenever a value in the first view changes (that you want to persist), you write it to Core Data or NSUserDefaults. Then, the new view reads the value as it needs it.
In your first view controller:
//A method to store the data
- (void)storeData:(id)pageID{
[[NSUserDefaults setObject:pageID forKey:#"pageID"];
}
- (void)showNewPPVC{
ProductPageViewController *ppvc = [[ProductPageViewController alloc] initWithNibName:#"ProductPageViewController" bundle:nil];
//Show and then release the PPVC
}
You can use custom initializers. - This is probably the most intuitive way to do it, once you understand the concept, because this is the only one where data is actually "passed". (As opposed to method 2 where no data is directly shared and method 1 where data is passed as a property.)
Notice that in the earlier examples, I used the initWithNibName:Bundle method. You might also notice that UITableViewControllers use a different initializer, initWithStyle:. Those two initializers take in some information for the new object so that it knows how to load. Let's look at the first one first:
- (id)initWithNibName:(NSString *)nibNameOrNil Bundle:(NSBundle *)bundleNameOrNil;
The first argument tells the view controller which nib file to load up. I'm going to ignore the second argument for now, since I've never seen anything passed in except nil. Moving right along to the second example:
- (id)initWithStyle:(UITableViewStyle)style;
You can pass in one of two UITableViewStyle values here. This is one way to define the style of a table view (the other way being to modify a nib file directly).
Let's extend this concept a bit to our example. I'm now going to show you how to make your own custom initializer. Let's initialize our ProductPageViewController instance:
- (id) initWithProductID:(int)productID;
That's simple enough. Now, we need to implement the method and actually do something with the product ID. We'll start with the barebones code here, required to "mimic" the functionality of the default initializer.
- (id) initWithProductID:(int)productID{
self = [super init];
return self;
}
This method will return an initialized copy of our ProductPageViewController, however, it won't load up our UI from a NIB yet, or if this were a UITableViewController, it wouldn't set the UITableViewStyle. Let's work with a NIB first and then I'll show how to work a UITableViewController. So...
- (id) initWithProductID:(int)productID{
self = [super initWithNibName:#"ProductPageViewController" Bundle:nil];
return self;
}
Now. we have an initialized ProductPageViewController, loaded from a NIB, but it doesn't do anything yet. Notice how we don't expose the NibName and Bundle arguments, but we just pass them in ourselves. If you want, you could theoretically expose those too. Now, let's take that productID and do something with it.
- (id) initWithProductID:(int)productID{
self = [super initWithNibName:#"ProductPageViewController" Bundle:nil];
if(self){
self.prodID = productID;
}
return self;
}
With our latest changes, our "PPVC" now knows about the productID. It can query the database as you want and do things with the results. You can then run different queries based on this productID.
Two More Quick Tips:
Perhaps you want to pass in several arguments. Of course you can simply add them to them method signature - (id) initWithProductID:(int)productID andCategoryID(int)categoryID, but what happens if you have five, six, or fifty six (yea, that's a lot) arguments? I'd advise passing in a collection or array of arguments.
To use custom initializers with UITableView, you pass in a UITableViewStyle instead of a NIB name. Here's what it might look like:
- (id) initWithProductID:(int)productID{
self = [super initWithStyle:UITableViewStyleGrouped];
if(self){
self.prodID = productID;
}
return self;
}
When making your subsections, I'd suggest a combination of persistent data and custom initializers. I also advise taking a peek at the viewDidLoad and viewWillAppear methods.

EXC_BAD_ACCESS on IPhone Cocos2d

I Have the following code:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack")
{
id action = [CCAnimate actionWithAnimation:[self animationByName:name]];
id repeatAction = [CCRepeat actionWithAction:action times:times];
currentAction = [self runAction:repeatAction];
lastANimation = currentAnimation;
currentAnimation = name;
}
else if(currentAction.isDone)
{
//Here is where I would change the animation
//but I commented the code for now
}
}
So when I run this and click on the button that changes the animation to "attack" (by calling [mysprite changeAnimation:#"attack" forTime:1];), I get a EXC_BAD_ACCESS error from the "currentAction.isDone" line, the next time the function is called (the joystick will call changeAnimation to try and change the animation to "run" or "idle", but I want the attack animation to finish first). Any thoughts on whyI get this? currentAction is declared in my class.
Edit: there is nothing in the rest of the class that interacts with currentAction, beside a getter. Its declaration is in the .h (CCAction* surrentAction). Do I need to initialize it? I thought the returned value from runAction would be sufficient? ANyways, when I run the debugger, it is not nil, and assigned to the correct action.
Thanks,
Dave
Edit:
I ended up creating a sequence when "attacking" that calls a function that changes the currentAnimation, so i avoided the issue. Still no idea what was happening.
Here's the answer if your interested:
Other Post
More of the class is probably needed to really answer this properly, but the EXC_BAD_ACCESS typically happens because you're accessing something that has been released and is no longer available in memory.
I'm guessing that somewhere in your class you're releasing, either explicitly, or implicitly, the "currentAction" object asynchronously - and when you're checking later, it's done & gone and you're hitting this crasher.
In general, keeping a state variable or two that you always have known values on is a good way to go, and for the "actions" that you're going through, if they're asynchronous and doing their own memory management, leave them as such and work through some state variables that you maintain and control all the memory management around. It's a pretty reasonable pattern for asynchronous callbacks, either with the classic stuff or as you move into using blocks with iOS 4.0