Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
lord funk
Feb 16, 2004

Doctor w-rw-rw- posted:

That strikes me as possibly incorrect?

In any case, setting hidden = YES should make the view hierarchy for the views you want to have 0 alpha not render. UIViewControllers usually remove or hide (not sure which) when they're not on top, but that is not necessarily the case for custom transitions.

Right - it was only when the alpha was not 1 or 0 that the slowdown occurred. I think I'm just at the limit for transparency (everything is transparent in that hierarchy).

Adbot
ADBOT LOVES YOU

Hughlander
May 11, 2005

I just wish that you could use enterprise as an internal alpha for all features. Not having Game Center sign on in an enterprise app sucks for my use case.

Doctor w-rw-rw-
Jun 24, 2008

lord funk posted:

Right - it was only when the alpha was not 1 or 0 that the slowdown occurred. I think I'm just at the limit for transparency (everything is transparent in that hierarchy).

1. Having a poo poo-ton of views will slow you down tremendously; UIViews are more expensive than you might think. On Paper we had a UIView->CALayer conversion effort for the things that didn't need user interaction.
2. http://www.objc.io/issue-5/iOS7-hidden-gems-and-workarounds.html With everything being transparent, you're going to incur a lot of compositing overhead on iOS7. Try disabling group opacity where applicable. Without group opacity, a layer with a non-zero-non-one opacity would render its children at full opacity then composite it with the layer's opacity (I might be slightly wrong on that, but close enough), whereas with it, sublayers inherit its opacity, which means much much more compositing.

Also possibly useful to look over: https://github.com/danielamitay/iOS-App-Performance-Cheatsheet/blob/master/QuartzCore.md

lord funk
Feb 16, 2004

Wow - disabling group opacity makes a huge difference in that view. HUGE. Jesus.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
https://www.youtube.com/playlist?list=PLb0IAmt7-GS2sh8saWW4z8x2vo7puwgnR

Paper tech talks. Watching the poo poo outta this.

Doctor w-rw-rw-
Jun 24, 2008

Feel free to ask me any questions if you need clarifications.

Doh004
Apr 22, 2007

Mmmmm Donuts...
Cool stuff.

fankey
Aug 31, 2001

Is there any way to work around the 'Multiple methods named 'x' found with mismatched result, parameter type or attributes' error? I made the unfortunate mistake of adding a scale property to a bunch of objects without a common base class and in the past I was able to iterate objects and set the scale with code like
Objective-C code:
if( [item respondsToSelector:@selector(setScale:)] )
{
  [item performSelector:@selector(setScale:) withObject:scaleFactor];
  // or
  [item setScale:scaleFactor];
}
but since upgrading to the latest version of Xcode I get the above error. It's conflicting with UIPinchGestureRecognizer and CAEmitterLayer properties. I'd rather not have to change my property to something like scaleFactor so it doesn't conflict.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Great talks!

I had gotten the impression that you guys had rewritten UIKit itself to be more concurrent... but now I'm relieved to see you still use it, but you do as much work as possible outside of it. If step 1 of creating a virtuoso app was "throw away UIKit", that'd be pretty damning.

Out of curiosity, how much does that actually improve performance in practice? Would the standard UIKit patterns give you 60fps on say, a 5S? Or is it truly important to run both cores as hot as possible? Do you have a switch you can flip to revert back to UIViews for everything?

Doctor w-rw-rw-
Jun 24, 2008

Filburt Shellbach posted:

Great talks!

I had gotten the impression that you guys had rewritten UIKit itself to be more concurrent... but now I'm relieved to see you still use it, but you do as much work as possible outside of it. If step 1 of creating a virtuoso app was "throw away UIKit", that'd be pretty damning.

Out of curiosity, how much does that actually improve performance in practice? Would the standard UIKit patterns give you 60fps on say, a 5S? Or is it truly important to run both cores as hot as possible? Do you have a switch you can flip to revert back to UIViews for everything?

Nope, the FBViewNode:UIView::UIView::CALayer analogy that Scott briefly touches on is basically the layer above UIKit. A *ton* of code involves layout, text, and image rendering, which happen to be the three major problems that FBViewNode was designed to address, and obviously three very major components of a very visual app.

The switch was basically a flag - isLayerBacked, or something like that. I think the part where it was usable as a non-rendered skeleton was talked about and work began around the time I left. The progression was pretty much: "We have tons of views. Let's benchmark against layers. Oh, it's way faster. Let's do that. (time passes) Oh, we can actually get rid of a ton of these layers since they're not terribly useful. Let's figure out strategies to do that."

The 5S is a terrible device to benchmark against since literally everything is fast on it. That said, even with its speed, if the main thread was blocked for more than 16ms at any given point in time, you'd get frame drops, on account of the client-side animation. The deeper the view hierarchy, the more extensive the layout, and the more certain you are to hit that 16ms threshold. Scott did mention that it was good for battery as maximizing concurrent operations (hopefully) minimizes total time the CPU needs to remain active, allowing it to shut down sooner when its work is done.

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.

fankey posted:

Is there any way to work around the 'Multiple methods named 'x' found with mismatched result, parameter type or attributes' error? I made the unfortunate mistake of adding a scale property to a bunch of objects without a common base class and in the past I was able to iterate objects and set the scale with code like
Objective-C code:
if( [item respondsToSelector:@selector(setScale:)] )
{
  [item performSelector:@selector(setScale:) withObject:scaleFactor];
  // or
  [item setScale:scaleFactor];
}
but since upgrading to the latest version of Xcode I get the above error. It's conflicting with UIPinchGestureRecognizer and CAEmitterLayer properties. I'd rather not have to change my property to something like scaleFactor so it doesn't conflict.

How many different classes with setScale? You can test for isKindOfClass and add the appropriate cast, but that still smells bad. You can cast to only one of the classes if the footprint is the same and you really want to save lines.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

Doctor w-rw-rw- posted:

Feel free to ask me any questions if you need clarifications.

What specifically did they open source from this effort?

fankey
Aug 31, 2001

ManicJason posted:

How many different classes with setScale? You can test for isKindOfClass and add the appropriate cast, but that still smells bad. You can cast to only one of the classes if the footprint is the same and you really want to save lines.
The error occurs even if I don't have any class of mine with setScale - just UIPinchGestureRecognizer and CAEmitterLayer conflict with each other. I think I'll just make a @protocol which all my classes implement to fix the issue but I'm still curious about my original question - it seems fragile that any class that happens to be included can break preformSelector.

Doctor w-rw-rw-
Jun 24, 2008

Ender.uNF posted:

What specifically did they open source from this effort?
The Paper team?

Origami, which the designers used to prototype UIs,
FBKVOController, which makes KVO better/safer,
Shimmer, which we used for the loading effects,
Tweaks, for tweaking values on the fly, such as the speed and bounciness constants in Pop, and for which one of the designers made a device bridge from Origami so he could test the parameters live,
Pop, which is in the final stages of open-sourcing prep work,
and likely the view node library, which they won't release until such time as they're sufficiently happy supporting the API for release. Scott, one of its creators (and the manager of the Paper team), is talking at f8 and may have more to say.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

fankey posted:

The error occurs even if I don't have any class of mine with setScale - just UIPinchGestureRecognizer and CAEmitterLayer conflict with each other. I think I'll just make a @protocol which all my classes implement to fix the issue but I'm still curious about my original question - it seems fragile that any class that happens to be included can break preformSelector.

Hopefully someone corrects me if I'm completely wrong but I think I know what is going on.

Objective-C method calls are translated by the compiler into C function calls. In order to pass any parameters along, the compiler needs to know each parameter's type so it can generate code that obeys the platform's calling conventions.

If the compiler knows the type of the receiver, it can look up the method signature for that type and get the information it knows. Otherwise (i.e. the type is id) it looks for any method signatures with the same selector. If only one is found, or if all the found method signatures match, the compiler again knows everything it needs to know. The problem you're seeing is when the compiler doesn't know the type of the receiver, and two different method signatures are found with identical selectors. Which one should it use? It can't decide with the information it has, and it refuses to guess, so it stops.

UIPinchGestureRecognizer and CAEmitterLayer each declare a method called -setScale: which takes a single parameter and returns nothing. -[UIPinchGestureRecognizer setScale:], however, takes a CGFloat as its parameter, while -[CAEmitterLayer setScale:] takes a float. These two types are different sizes on 64-bit architectures. Since you haven't specified the type of the receiver, the compiler doesn't know how to call -setScale: and gives up. To work around it, you need to resolve this ambiguity for the compiler.

If you know what you've got, you can cast it:
Objective-C code:
[(CAEmitterLayer *)item setScale:2]; // takes a float
[(UIPinchGestureRecognizer *)item setScale:2]; // takes a CGFloat
(Note that the actual type of item doesn't matter so long as the method signature is the same as the type you cast it to.)

If you don't know in advance whether your item takes a float or a CGFloat, you'll either need to fiddle with method signatures at runtime (probably a bad idea) or refactor your code somewhat (e.g. add -[CAEmitterLayer fankey_setScale:] in a category and have it take a CGFloat, then implement the same method in whatever other classes you want).

ultramiraculous
Nov 12, 2003

"No..."
Grimey Drawer

pokeyman posted:

Hopefully someone corrects me if I'm completely wrong but I think I know what is going on.

Objective-C method calls are translated by the compiler into C function calls. In order to pass any parameters along, the compiler needs to know each parameter's type so it can generate code that obeys the platform's calling conventions.

If the compiler knows the type of the receiver, it can look up the method signature for that type and get the information it knows. Otherwise (i.e. the type is id) it looks for any method signatures with the same selector. If only one is found, or if all the found method signatures match, the compiler again knows everything it needs to know. The problem you're seeing is when the compiler doesn't know the type of the receiver, and two different method signatures are found with identical selectors. Which one should it use? It can't decide with the information it has, and it refuses to guess, so it stops.


This is close to right. The method calls are turned into variants of objc_msgsend, rather than direct calls to the implementation. The compiler has several variations of objc_msgsend to choose from, which are all written in assembly and take different parameter/return types. The compiler generally appears to fail out when the sizes of the return/parameter types vary. In fankey's case setScale: can take either a float or a CGFloat (which is a double for ARM64), depending on the class declaring the method.

That's at least my understanding of how this works and how it can get messy, mostly based on Mike Ash's post.


Edit:
As a simple example: http://pastebin.com/VHsEikWf

If you try and compile that code for 64bit, the compiler gives an error on the setFloat: method, but none of the others. If you compile it for 32bit only, it's fine.

ultramiraculous fucked around with this message at 18:39 on Apr 22, 2014

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

ultramiraculous posted:

This is close to right. The method calls are turned into variants of objc_msgsend, rather than direct calls to the implementation. The compiler has several variations of objc_msgsend to choose from, which are all written in assembly and take different parameter/return types. The compiler generally appears to fail out when the sizes of the return/parameter types vary. In fankey's case setScale: can take either a float or a CGFloat (which is a double for ARM64), depending on the class declaring the method.

That's at least my understanding of how this works and how it can get messy, mostly based on Mike Ash's post.

I thought the only reason for variants of objc_msgSend was to handle return types. From your linked post:

Mike Ash posted:

Because [objc_msgSend] simply looks up the right code and then jumps directly to it, it's relatively generic. It works with any combination of parameters passed to it, because it just leaves them alone for the method IMP to read. Return values are a bit trickier, but it turns out that every possible return type can be accounted for with just a couple of variants of objc_msgSend.

The right method signature is needed in fankey's case to make sure the parameters are passed according to the platform's calling convention, but that has nothing to do with objc_msgSend.

Doctor w-rw-rw-
Jun 24, 2008

pokeyman posted:

The right method signature is needed in fankey's case to make sure the parameters are passed according to the platform's calling convention, but that has nothing to do with objc_msgSend.
For clarification (I'm sure you know this, but others might not)
objc_msgSend and objc_msgSend_stret and _fpret exist for return conventions: http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html

If memory serves, this can cause ABI funkiness based on the bitness of the system, since 64-bit values can be returned on those systems without the stret variant of obcc_msgSend.

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.
performSelector causes frequent oddities, especially in ARC. I often run into the unknown return type warning and end up fixing it with code as beautiful as:
Objective-C code:
IMP imp = [[delegate class] instanceMethodForSelector:delegateSelector];
void (*func)(id, SEL, HTTPDiagnostic *) = (void *)imp;
func(delegate, delegateSelector, self);
Instead of
Objective-C code:
[delegate performSelector:delegateSelector]
which gives the warning.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
If you're using Objective-C++ you can do:
Objective-C code:
template<typename Ret, typename... Args>
Ret performSelector(SEL selector, id obj, Args&&... args) {
    IMP imp = [obj methodForSelector:selector];
    return ((Ret (*)(Args...))imp)(obj, selector, std::forward<Args>(args)...);
}

performSelector<void>(delegate, delegateSelector);
Still breaks horribly at runtime if the arguments are of incorrect types, unfortunately.

Doctor w-rw-rw-
Jun 24, 2008

ManicJason posted:

performSelector causes frequent oddities, especially in ARC. I often run into the unknown return type warning and end up fixing it with code as beautiful as:
Objective-C code:
IMP imp = [[delegate class] instanceMethodForSelector:delegateSelector];
void (*func)(id, SEL, HTTPDiagnostic *) = (void *)imp;
func(delegate, delegateSelector, self);
Instead of
Objective-C code:
[delegate performSelector:delegateSelector]
which gives the warning.

Alternatively, just silence clang:

Objective-C code:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// performSelector call here
#pragma clang diagnostic pop

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.
Yeah, I usually choose the ugly fix over quashing the warning because it makes the compiler happier and still works if you have a return value or many arguments.

I also enjoy committing code that makes my coworkers vomit.

Doh004
Apr 22, 2007

Mmmmm Donuts...
gently caress delegates, use more blocks.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
You can just cast objc_msgSend unless (1) the method returns a struct or (2) you actually care about getting the correct behavior for messaging nil.

We probably ought to provide a builtin that selects the right messenger function, even for indirect results. performSelector is so terrible.

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.
The ugly IMP way doesn't work for nil either as I wrote it.

Doctor w-rw-rw-
Jun 24, 2008
Just a small tip of the day - something I learned when I fixed a bug in the jewel bar on the Facebook app and Paper several months ago:

Objective-C code:
@interface UIView (Slop)
@property (nonatomic, assign) UIEdgeInsets hitSlop;
@end
Objective-C code:
#import "UIView+Slop.h"

@import ObjectiveC;

static const void *UIViewHitSlopKey = &("UIViewHitSlopKey");

@implementation UIView (Slop)

- (UIEdgeInsets)hitSlop
{
    NSValue *value = objc_getAssociatedObject(self, UIViewHitSlopKey);
    if (value) {
        return [value UIEdgeInsetsValue];
    } else {
        return UIEdgeInsetsZero;
    }
}

- (void)setHitSlop:(UIEdgeInsets)hitSlop
{
    NSValue *value = [NSValue valueWithUIEdgeInsets:hitSlop];
    objc_setAssociatedObject(self, UIViewHitSlopKey, value, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method hitTestOrig = class_getInstanceMethod([UIView class], @selector(pointInside:withEvent:));
        Method hitTestSlop = class_getInstanceMethod([UIView class], @selector(customPointInside:withEvent:));
        method_exchangeImplementations(hitTestOrig, hitTestSlop);
    });
}

- (BOOL)customPointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL pointInside = [self customPointInside:point withEvent:event]; // because of swizzling, this uses the default IMP
    if (pointInside) {
        return YES;
    }

    CGRect bounds = self.bounds;
    CGRect sloppedRect = UIEdgeInsetsInsetRect(bounds, self.hitSlop);
    return CGRectContainsPoint(sloppedRect, point);
}

@end
Give the new hitSlop property some negative insets, and your buttons gain a certain amount of leeway for touches. It's pretty useful when you want to precisely position a button (or view acting as one), but want to be forgiving in your touch area.

Doh004
Apr 22, 2007

Mmmmm Donuts...
Anyone else use XCTool?

I'm trying it out and trying to integrate it with our TeamCity server for our automated tests. I've been trying to write my own reporter to format the output so that TeamCity can read it correctly. It's "working", however, I only ever get the messages from the reporter all the way at the end of the tests and not as they occur. Am I doing something wrong here?

This happens even when running locally and not just in TC.

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.

Doctor w-rw-rw- posted:

Objective-C code:
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method hitTestOrig = class_getInstanceMethod([UIView class], @selector(pointInside:withEvent:));
        Method hitTestSlop = class_getInstanceMethod([UIView class], @selector(customPointInside:withEvent:));
        method_exchangeImplementations(hitTestOrig, hitTestSlop);
    });
}
Do you really need a dispatch_once inside of load? It certainly won't hurt anything, but I'm wondering if something odd happened and it's really needed.

That slop is a neat trick I may steal.

Doctor w-rw-rw-
Jun 24, 2008

ManicJason posted:

Do you really need a dispatch_once inside of load? It certainly won't hurt anything, but I'm wondering if something odd happened and it's really needed.

That slop is a neat trick I may steal.

Probably not - I moved that specific block of code around when writing it, and it got hit twice once, so I just wrapped it.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

ManicJason posted:

Do you really need a dispatch_once inside of load? It certainly won't hurt anything, but I'm wondering if something odd happened and it's really needed.

That slop is a neat trick I may steal.

You don't need it. Relevant Friday Q&A.

Doctor w-rw-rw-
Jun 24, 2008

Sweet, thanks for that! I already knew it was called once, but only assumed the category +load special case without knowing for sure.

ManicJason
Oct 27, 2003

He doesn't really stop the puck, but he scares the hell out of the other team.
I spent an afternoon writing code that relied on a category +load being called multiple times, once for each of its subclasses, before I learned I was wrong. That was a fun day.

FUCKFACE MORON
Apr 23, 2010

by sebmojo
Wasn't sure whether or not to start a new thread or post this in here. In any case I posted this thread in BFC like a loving idiot: http://forums.somethingawful.com/showthread.php?threadid=3628186

Your guidance is appreciated :shobon:

Doctor w-rw-rw-
Jun 24, 2008

Chris Gaines posted:

Wasn't sure whether or not to start a new thread or post this in here. In any case I posted this thread in BFC like a loving idiot: http://forums.somethingawful.com/showthread.php?threadid=3628186

Your guidance is appreciated :shobon:

Build poo poo and ask us questions.

FUCKFACE MORON
Apr 23, 2010

by sebmojo
Fair enough

dizzywhip
Dec 23, 2005

I started in Mac development, and I just read the Mac equivalent of this which was enough to get me going. I'm sure the iOS book is of similar quality.

FUCKFACE MORON
Apr 23, 2010

by sebmojo
Thanks for the tip! The iOS "Boot Camp" I was in provided a solid foundation to build on, so that book should really help.

FUCKFACE MORON fucked around with this message at 10:04 on Apr 24, 2014

eschaton
Mar 7, 2007

Don't you just hate when you wind up in a store with people who are in a socioeconomic class that is pretty obviously about two levels lower than your own?

Chris Gaines posted:

Thanks for the tip! The iOS "Boot Camp" I was in provided a solid foundation to build on, so that book should really help.

Did you have a development background going into this, or are you also brand new to writing software?

If you're new, remember that software development is a field where someone coming out of a very good four-year degree program—such as CMU, MIT, or Stanford— is considered junior.

FUCKFACE MORON
Apr 23, 2010

by sebmojo
I earned a Computer Science degree from the Colorado School of Mines in 2002, so I do have the background as far as programming goes. That said, I currently consider myself at the junior level as far as iOS development goes.

Adbot
ADBOT LOVES YOU

kitten smoothie
Dec 29, 2001

Really, though, this

Doctor w-rw-rw- posted:

Build poo poo and ask us questions.

is the best advice. Make something that scratches your personal itch, don't care whether it's marketable, just make something for yourself. It'll probably suck, but you'll have learned something. Then do that again keeping in mind what you learned. Repeat.

I moved into mobile development as a fulltime career last summer. I previously had 10 years' professional experience under my belt as a bioinformatics programmer and a brief time working for an ERP company as a consultant. I started goofing off with the iOS SDK when I had some bench time on the consulting job. I made a couple things for myself to learn, I did a couple freelance projects, and shipped an app or two on the store myself. I started going to a local mobile dev meetup and gave a talk or two there.

I never really intended to make it into a full time thing, but last June I had a poo poo day at work and emailed the leader of the mobile dev meetup if he'd refer me into his company. Two weeks later I was hired to do iOS full time.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply