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
pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

Mainly there's just stale data in there and it's almost worse to have that vs. just having nothing at all. Plus it seems like all the calls have to be async and that just adds a lot of extra boilerplate/indenting (thus my question about promises earlier this week)

This project isn't using ViewModels at all and is mostly powered by a handful of really big view controllers. I don't want to slag off the contractor that we're working with because this is my first iOS/Swift project and he's been doing this since 2010 or so and I've learned a ton about iOS working with him but he just has a higher tolerance for like 1000-line classes that do a whole lot of stuff than I do.

That approach sounds interesting though, so essentially your ViewModel or VC has an initializer where you pass in the currentUser? Do you then save that as an instance variable within the class? If so how do you keep that in sync? The instance var would be a copy and not a direct reference, right?

Core Data model objects (NSManagedObject and subclasses) are reference types and keep themselves up-to-date with any changes to their context. You can observe changes to individual objects with key-value observing, and to fetch requests using NSFetchedResultsController. When you're providing stuff via initializers, you can pass the NSManagedObjectContext instance, or just pass in e.g. the user object (which has a reference to its context if you need it for subsequent fetching). Then keep it around in an instance variable yeah, and use KVO/FRC to know when to update the UI.

Adbot
ADBOT LOVES YOU

Doc Block
Apr 15, 2003
Fun Shoe

awesomeolion posted:

My guess is that there's some Spritekit bug related to figuring out a reasonable drawing order when sprites on the same z position.

If there’s any sanity to SpriteKit’s implementation, z position is just used for sorting. It’s not like they’re enabling depth testing and you’re getting z-fighting problems. Two objects having the same Z value shouldn’t have any effect; the second one should just get drawn on top of the first.

quote:

I've now run full speed into the next issue... spawning obstacles on a timer and dropping my frame rate from 60 to 8 to freezing. So far my impression of going from Unity to SpriteKit is that it's very foot-gun-y. Which I guess makes sense because Unity is pretty idiot-proof. Anyways, something to debug next time!

Adding and removing nodes constantly is going to be slow, especially if you’re also doing a bunch of your own initialization stuff. The worst case is that SpriteKit has to allocate memory for a new node array, copy everything over, and then re-sort it by Z value.

Keep a handful of “dead” objects around and parented to your scene, but either hidden or positioned offscreen, then when you need a new one use one of those, and when removing an object make it one of the dead objects.

Or, if you’re adding all objects as direct children of the scene, instead break your scene apart into layers. Use a separate SKNode for each layer of your scene, and add/remove objects from those, which will limit the amount of work SpriteKit has to do when adding/removing objects to that particular SKNode instead of having to re-sort the whole scene.

prom candy
Dec 16, 2005

Only I may dance

pokeyman posted:

Core Data model objects (NSManagedObject and subclasses) are reference types and keep themselves up-to-date with any changes to their context. You can observe changes to individual objects with key-value observing, and to fetch requests using NSFetchedResultsController. When you're providing stuff via initializers, you can pass the NSManagedObjectContext instance, or just pass in e.g. the user object (which has a reference to its context if you need it for subsequent fetching). Then keep it around in an instance variable yeah, and use KVO/FRC to know when to update the UI.

Oh drat, okay I think I need to back up and read some docs or focused tutorials on CoreData. This does not appear to be how we're using it in our app at all. Thanks!

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

Oh drat, okay I think I need to back up and read some docs or focused tutorials on CoreData. This does not appear to be how we're using it in our app at all. Thanks!

I've seen people use Core Data as a glorified object-relational mapper, and they'll pull data from managed objects into structs or plain old NSObjects and pass those around instead. To put it mildly, this pattern does not play to Core Data's strengths, but it can work well enough. I can see the argument when building a library or something where Core Data might be an implementation detail you want to hide, but when you're building your app around it it's harder to justify.

I'm not saying you should go off on your contractor about it or anything, but yeah if y'all are building your own change management and stuff on top of Core Data then it's worth getting clear on the reasons for doing it that way.

prom candy
Dec 16, 2005

Only I may dance

pokeyman posted:

I've seen people use Core Data as a glorified object-relational mapper, and they'll pull data from managed objects into structs or plain old NSObjects and pass those around instead. To put it mildly, this pattern does not play to Core Data's strengths, but it can work well enough.

Yeah that's exactly what we're doing. We're just running into problems where you might push a viewcontroller that updates an object in CoreData, and now when you go back in the navigation stack it's not updated on the VC from before so you need to do a bunch of bespoke checking-and-reloading when your views load/appear.

We're really close to launch and since I'm not a subject matter expert I'm not going to rock the boat. After we launch I'll be taking over the project entirely and I plan on just refactoring it as I learn more. It's a bit of an awkward situation because we're both senior level developers and he obviously knows way more about the iOS ecosystem than I do, but at the same time I'm not wild about some of the ways he writes and organizes code. So there's been a lot of doubt on my side about whether something that looks off to me is an "iOS thing" or a "this guy thing" and I don't really want to get it into it either way because if I was in his shoes contracting for a company that puts one of their developers on the project with you halfway through who doesn't know the ecosystem and is extremely opinionated doesn't sound like a great time. So I'm trying to just go with the flow and then I'll figure out if there are better ways to handle certain things after his contract is done.

lord funk
Feb 16, 2004

Glimm posted:

Does anyone use Applanga or a similar tool to handle translations? Any thoughts on it?

I saw a demo from them recently and like most marketing demos it looked a little too good to be true, but still probably useful.

I don't know anything about Applanga, but I've used Applingua for translation before, and they did a good job.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Doc Block posted:

If there’s any sanity to SpriteKit’s implementation, z position is just used for sorting. It’s not like they’re enabling depth testing and you’re getting z-fighting problems. Two objects having the same Z value shouldn’t have any effect; the second one should just get drawn on top of the first.


Adding and removing nodes constantly is going to be slow, especially if you’re also doing a bunch of your own initialization stuff. The worst case is that SpriteKit has to allocate memory for a new node array, copy everything over, and then re-sort it by Z value.

Keep a handful of “dead” objects around and parented to your scene, but either hidden or positioned offscreen, then when you need a new one use one of those, and when removing an object make it one of the dead objects.

Or, if you’re adding all objects as direct children of the scene, instead break your scene apart into layers. Use a separate SKNode for each layer of your scene, and add/remove objects from those, which will limit the amount of work SpriteKit has to do when adding/removing objects to that particular SKNode instead of having to re-sort the whole scene.

Your suggestions are working nicely! Toggling isHidden instead of adding/removing seems to help performance. Also I'm using node.intersects each frame instead of physics collisions and that seems to perform way better. Cheers :)

prom candy
Dec 16, 2005

Only I may dance
Apple approved our app! Thanks for all the help (so far) thread. Even though I've deployed a zillion web applications it feels exciting to have something in the App Store.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Fantastic, congratulations! And I know what you mean, there's a little something extra about deploying through a capricious review process :)

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Trying to fill out the app store privacy labels for Awful and I have no idea what they're aiming for. Does sending your username to SA to log you in count as linking your user ID to your identity? Are your posts tied to your identity because SA had an email address on file for your account? And if I can't opt out of Apple keeping crash reports for me, why is it optional to add "crash reports" to the privacy label?

(The answers I came up with are "do whatever Twitteriffic does" for the first two and "I guess Apple is a second party and these questions are about first and third parties?" for the third.)

(Also the privacy labels seem like a bit of a joke.)

lord funk
Feb 16, 2004

It'd be super nice if the App Store screenshot section actually told me which device produces the exact resolution they want instead of making me guess which of the 50 simulators is 5.5".

jabro
Mar 25, 2003

July Mock Draft 2014

1st PLACE
RUNNER-UP
got the knowshon


lord funk posted:

It'd be super nice if the App Store screenshot section actually told me which device produces the exact resolution they want instead of making me guess which of the 50 simulators is 5.5".

I know what you mean. Here is a resource to help alleviate their laziness if you don't have something like this.

https://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions

lord funk
Feb 16, 2004

Thanks, yeah I had to find a website to help out. It's just dumb that it's not at all clear in the actual screenshots area of App Store Connect.

Speaking of dumb complaints: thanks Xcode for giving me a warning for EACH AND EVERY OPENGL FUNCTION IN MY APP. Yes, I know it's deprecated. No, I'm not rewriting my graphics engine, and 695 warnings won't make me.

prom candy
Dec 16, 2005

Only I may dance
Do you guys precompile your pods? Or is there something else I can do to speed these builds up? Any time I change configuration or targets my builds take like 5min and the bulk of it is CocoaPods

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I don't precompile anything, but I change configurations and targets very rarely so it doesn't bother me. What are you changing so frequently?

Also, one fix is to use fewer dependencies :)

lord funk
Feb 16, 2004

Well gently caress. Looks like running my app on iOS 14 causes saved files to have data payloads of nothing because of deprecated keyed archiving. Awesome! Glad my data is more secure because of the move to NSSecureCoding!

gently caress.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
There were a few projects which let you build a pod as a framework and import that instead, but I don't think any have made the transition to xcframeworks yet so they don't really work any more.

Using ccache can eliminate lots of spurious rebuilds that didn't actually need to rebuild things.

KidDynamite
Feb 11, 2005

lord funk posted:

Well gently caress. Looks like running my app on iOS 14 causes saved files to have data payloads of nothing because of deprecated keyed archiving. Awesome! Glad my data is more secure because of the move to NSSecureCoding!

gently caress.

I just changed over to archivedData:withRootObject:requiringSecureCoding and it was a pain in the rear end because it's a bunch of extra code. I had no idea ios 14 broke things though that sure is something.


I'm in a lot of pain because you can't generate an appstoreconnect api key for an enterprise account and apple now enforces 2fa so all the automation i just finished setting up is broken. literally got one build out with automation.

Keebler
Aug 21, 2000
Hi folks. First time using Cocoa/Objective-C and I'm in the process of porting an emulator I wrote with X11/OpenGL in a Linux environment to macos. I'm using a xib based project (which I'm thinking may have been a mistake at this point). My main xib contains the menu as well as the main window with a subclassed mtKView. This works find and the menu selections are handled by a subclassed NSViewController. There is also a second xib file that contains only a simple preferences window for when the user selects the "Preferences..." option from the app menu. This where I'm stuck. I get the window to open using the following code from the view controller:

code:
- (IBAction)settings:(id)sender
{
    _settings = [ [NSWindowController alloc] initWithWindowNibName:@"Settings" ];
    
    [ [_settings window] makeKeyAndOrderFront:sender ];
}
The window shows up visually on top of the main window as desired but it lacks the focus (key?). The title bar is greyed out until I click on it. For grins I queried canBecomeKeyWindow for the window and it returns false. Anyone know what might be going on? There's nothing special option wise with this window, normal border, normal title bar, etc. I gotta believe I'm either doing something wrong or misunderstanding something basic.

Glimm
Jul 27, 2005

Time is only gonna pass you by

KidDynamite posted:

I'm in a lot of pain because you can't generate an appstoreconnect api key for an enterprise account and apple now enforces 2fa so all the automation i just finished setting up is broken. literally got one build out with automation.

Do Xcode bots offer anything in the way of solving this?

It's a travesty folks have to rely on tools like Fastlane to do the simplest CI things for Apple development. It's like anything more than a single developer wasn't planned for.

Dirk Pitt
Sep 14, 2007

haha yes, this feels good

Toilet Rascal

KidDynamite posted:

I just changed over to archivedData:withRootObject:requiringSecureCoding and it was a pain in the rear end because it's a bunch of extra code. I had no idea ios 14 broke things though that sure is something.


I'm in a lot of pain because you can't generate an appstoreconnect api key for an enterprise account and apple now enforces 2fa so all the automation i just finished setting up is broken. literally got one build out with automation.

Don’t one time passwords work?

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
App specific passwords are only supported for a very limited subset of things.

fankey
Aug 31, 2001

In objc, is there an easy way to chain multiple NSURLSession.dataTaskWithURL calls? I need to do something like this procedural pseudo code
code:
data = HttpGetData(someUrl); // call that gets some data structure via HTTP

List<Foo> foos;
foreach(foo in data.foos)
  foos.add( HttpGetFoo(foo));

List<Bar> bars;
foreach(bar in data.bars)
  bars.add( HttpGetBar(bar, foos));

CallSomeFunction( foos, bars )
In C# async land this is trivial. Trying to chain together completionHandlers to then trigger the next step in the process is ugly, especially if different parts of the process need different arguments and are handled by different classes. Is there anything built in or available via a lightweight 3rd party lib that can help make this easier to deal with?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Nothing easy or lightweight that I know of. My first instinct is to reach for something like PromiseKit.

prom candy
Dec 16, 2005

Only I may dance
Do you need them to run in order or do you just want to fire off two async calls and then run some code when both are complete? I haven't done it yet but I was just googling this same issue today and it seemed to point to using DispatchGroup. I only work in Swift but I think it exists in Obj-C as well. The thing that makes it nice to use might only exist in Swift though, I'm not sure.

fankey
Aug 31, 2001

Thanks for the input. I'd prefer that they run in order so I don't have to worry about 429 errors or something similar. I don't really need to load things as fast and as parallel as possible. There might be a different approach - let me explain better what I'm trying to accomplish.

I'm loading a bunch of images from an HTTP server. The current version of the app creates a separate dispatch_queue_t, uses CGImageSourceCreateWithURL to create the images and once finished makes a callback back to the dispatch_get_main_queue to notify the UI that the images have been loaded. This worked perfectly fine until we wanted to use HTTPS instead of HTTP to load the images. Because this server is an internal network appliance the certs will either be self signed or likely not installed on the iOS device. Since the certs can't be verified CGImageSourceCreateWithURL fails due to TLS issues. I do know that I can automatically trust the cert when using the URLSession:didReceiveChallenge callback. Is there a way to accomplish the same without using the async URLSession methods?

Centrist Committee
Aug 6, 2019
Haha yeah I’m trying to roll my own rate limiter too. I’m sure Alamofire or some other library does it but I want to stick to vanilla Swift if possible

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

fankey posted:

Thanks for the input. I'd prefer that they run in order so I don't have to worry about 429 errors or something similar. I don't really need to load things as fast and as parallel as possible. There might be a different approach - let me explain better what I'm trying to accomplish.

I'm loading a bunch of images from an HTTP server. The current version of the app creates a separate dispatch_queue_t, uses CGImageSourceCreateWithURL to create the images and once finished makes a callback back to the dispatch_get_main_queue to notify the UI that the images have been loaded. This worked perfectly fine until we wanted to use HTTPS instead of HTTP to load the images. Because this server is an internal network appliance the certs will either be self signed or likely not installed on the iOS device. Since the certs can't be verified CGImageSourceCreateWithURL fails due to TLS issues. I do know that I can automatically trust the cert when using the URLSession:didReceiveChallenge callback. Is there a way to accomplish the same without using the async URLSession methods?

Are you just trying to get the images to appear in the UI, or are you downloading them for safekeeping? If the former, a library like Nuke might be convenient.

You could probably make your own CGDataProvider with callbacks that do the cert stuff if you really wanted to, but I've never had much fun doing anything custom with one-stop functions like CGImageSourceCreateWithURL or methods like -[NSData dataWithContentsOfURL:]. NSURLSession is probably the way to go.

Maybe an object that creates an NSURLSession and acts as its delegate? When you submit a batch of images to download, you could spin up all the NSURLDownloadTasks and make note of their IDs. As they finish, you can check if the batch is all done and notify some callback. There are NSURLSessionConfiguration properties if you want to fiddle with concurrent requests and such.

I guess I should mention NSOperationQueue, it's a built-in async thing that supports dependencies and completion blocks. I have always found it incredibly hard to use with other async things (such as NSURLSession), but it's there.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
The way to write that kind of loop with a completion handler is to "tie the knot" with some declared function, like

Swift code:
private class MapAsyncHelper<Iterator: IteratorProtocol, R> {
  var iterator: Iterator
  let operation: (Element, (R) -> ()) -> ()
  let completion: ([R]) -> ()
  var results = [R]()

  func run() {
    if let element = iterator.next() {
      operation(element) { result in
        results.append(result)
        run()
      }
    } else {
      completion(results)
    }
  }
}

extension Sequence {
  func mapAsync<R>(operation: (Element, (R) -> ()) -> (), completion: ([R]) -> ()) {
    MapAsyncHelper(iterator: makeIterator(), operation: operation, completion: completion).run()
  }
}

myArray.mapAsync { element, completion in
  myAsyncThing(element, completion)
} completion: { results in
  ...
}
Obviously this gets much easier with async/await, and you'd need to do some extra work to handle errors.

rjmccall fucked around with this message at 00:33 on Mar 4, 2021

fankey
Aug 31, 2001

That looks pretty fancy. Unfortunately I haven't bothered to learn Swift yet so to me it's mumbo jumbo :shrug:

Here's something that I came up with. Seems to work and is lacking in a bunch of error handling. It's a class you can hand a bunch of URLs, tell to go and get told when it's done. It looks like it may be kind of similar to what you were suggesting.
code:
@interface DataDownloader : NSObject<NSURLSessionDelegate>
{
  NSMutableDictionary<NSString*,NSURL*>* queue;
  NSMutableDictionary<NSString*,NSData*>* data;
  NSURLSession* session;
}
typedef void(^download_complete)(NSDictionary<NSString*,NSData*>*);
@property (nonatomic) download_complete completion;

@end
@implementation DataDownloader
-(id)init
{
  if(self = [super init])
  {
    queue = [[NSMutableDictionary<NSString*,NSURL*> alloc] init];
    data = [[NSMutableDictionary<NSString*,NSData*> alloc] init];
    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
  }
  return self;
}

-(void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
  if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
    
    NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
  }
}

-(void)addUrl:(NSURL*)url forKey:(NSString*)key
{
  [queue setObject:url forKey:key];
}
-(void)go
{
  if(queue.allKeys.count > 0)
  {
    NSString* key = queue.allKeys[0];
    NSURL* url = queue[key];
    [queue removeObjectForKey:key];
    NSURLSessionDataTask *task = [session
      dataTaskWithURL:url
    completionHandler:^(NSData *dt, NSURLResponse *response, NSError *err)
    {
      if(err)
      {
        NSLog(@"ERROR : %@", err);
      }
      else
      {
        [self->data setObject:dt forKey:key];
      }
      [self go];
    }];
    [task resume];
  }
  else
  {
    dispatch_async(dispatch_get_main_queue(), ^{
      self.completion(self->data);
    });
  }
}
@end

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Looks ok to me, so long as you don't call -addUrl:forKey: after calling -go (otherwise you're accessing queue concurrently).

prom candy
Dec 16, 2005

Only I may dance
I have a screen that's a static top bar and then a UICollectionView with a grid of items underneath it that scrolls forever (or until it runs out of items). I need to add a new section above the UICollectionView that uses horizontal scrolling to display some other items. Sometimes this section won't be there (if there are no items to put in it). Basically you can think of it like a products page, with some featured products at the top.

The current layout is basically this

code:
Root
  - TopContainerView
  - UICollectionView
What I'm thinking I probably need is this:

code:
Root
  - TopContainerView
  - UIScrollView
    - UIStackView (to make it easy to toggle the the top section on and off)
      - UICollectionView (Horiztonal Scrolling)
      - UICollectionView (The grid of stuff, no longer manages its own scrolling)
However, I've also seen some stuff about UICollectionViewCompositionalLayout and I'm not sure if that's a better way to handle these types of views or if I can accomplish what I'm after using a single UICollectionView with multiple sections. It's also worth noting that the existing grid view is already broken into sections (groups of items are split up underneath date headings)

Edit: Looks like UICollectionViewCompositionalLayout does exactly what I want

prom candy fucked around with this message at 19:46 on Mar 4, 2021

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Yep, you want compositional layout.

prom candy
Dec 16, 2005

Only I may dance
So these classes seem powerful as hell, feels like you could use these for any complex layout even if you were presenting mostly static data. Is that something that people do now or are stackviews and scrollviews still the way to go? I also checked out the new(ish) UICollectionView/TableViewDiffableDataSource talk from the same WWDC and that also looks like an upgrade over delegation. The guy who built our app for us didn't use them anywhere though, do they have downsides?

take boat
Jul 8, 2006
boat: TAKEN
at my job we typically use stack views contained within scroll views, though we don't generally deal with long lists of user-generated content so this works out okay

we also do things like using wrapping views to add insets vOv

I would suggest using collection views for any layout beyond a single screen if possible, though

edit: one big downside with UITableViewDiffableDataSource / UICollectionViewDiffableDataSource is that they're iOS 13+ only. we're getting to the point where that's a pretty reasonable requirement (especially if you're looking to use SwiftUI), but for many apps that's still a problem

take boat fucked around with this message at 08:15 on Mar 5, 2021

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

So these classes seem powerful as hell, feels like you could use these for any complex layout even if you were presenting mostly static data. Is that something that people do now or are stackviews and scrollviews still the way to go? I also checked out the new(ish) UICollectionView/TableViewDiffableDataSource talk from the same WWDC and that also looks like an upgrade over delegation. The guy who built our app for us didn't use them anywhere though, do they have downsides?

I'm morally opposed to using collection view or table view for layouts that never reuse cells, but I don't have a good reason. For example, if you're making a screen with four components that are all always visible (modulo small screens or a keyboard, so they're still in a scroll view) then a collection view feels silly? But if it gets the job done, sure.

take boat posted:

at my job we typically use stack views contained within scroll views, though we don't generally deal with long lists of user-generated content so this works out okay

we also do things like using wrapping views to add insets vOv

I would suggest using collection views for any layout beyond a single screen if possible, though

edit: one big downside with UITableViewDiffableDataSource / UICollectionViewDiffableDataSource is that they're iOS 13+ only. we're getting to the point where that's a pretty reasonable requirement (especially if you're looking to use SwiftUI), but for many apps that's still a problem

I learned to love layout margins, but they have odd interactions with stack views sometimes (haven’t quite shrunk that down to a small reproduction, unfortunately) so manual insets aren't always so bad.

As for the minimum SDK version, this diffable data source backport seems to work quite well (using it for a settings screen): https://github.com/ra1028/DiffableDataSources goes back to iOS 9. There's also a compositional layout backport at https://github.com/kishikawakatsumi/IBPCollectionViewCompositionalLayout back to iOS 10 but I have not tried it.

lord funk
Feb 16, 2004

Just ran into the bug where network access permissions are missing, and there's no way to reset it.

I'm already annoyed at the barrage of permissions popups that happen when you open an app for the first time (great user experience!). But now I can't even get those to appear. Awesome.

prom candy
Dec 16, 2005

Only I may dance
I just found out about Swift keypaths, that seems super powerful. Also it's been a slog because I'm refactoring and adding on to an existing UICollectionView that I didn't create rather than starting from scratch but UICollectionViewDiffableDataSource and UICollectionViewCompositionalLayout are very cool once you wrap your head around them.

prom candy
Dec 16, 2005

Only I may dance
I need to build a layout and I'm a bit unsure of how to do it. I have a card-like design that can grow until it takes up the full height of the screen. The content is made up of a title, and then some dynamic content. If the content is greater than the length of the screen I want to be able to do an inner scroll of the content itself, while the title (and the card itself) stays in place.

What I've tried is making the card itself a UIStackView, and adding the title as a UILabel. After that, I add a UIScrollView to the stack view, and then add the content to the UIScrollView. The thing I can't figure out is how to tell the UIScrollView that it can grow until the outer stack view reaches its max height (set with a lessThanOrEqualTo constraint) at which point it needs to become scrollable instead.

Here's a crude ascii representation of a shorter amount of content as well as a longer amount of content. Any ideas? Do I need to calculate the size of my content/card container or can I do this with autolayout?

code:

|-------------------|   
| TITLE             |
|                   |
| |---------------| |
| | No            | |
| | Scrolling     | |
| | Required      | |
| |---------------| |
|-------------------|   

|-------------------|   
| TITLE             |
|                   |
| |---------------| |
| | Max           | |
| | Limit         | |
| | Hit           | |
| | So            | |
| | Now           | |
| | Scrolling     | |
| | is            | |
| |---------------| |
|-------------------|   

Adbot
ADBOT LOVES YOU

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

I need to build a layout and I'm a bit unsure of how to do it. I have a card-like design that can grow until it takes up the full height of the screen. The content is made up of a title, and then some dynamic content. If the content is greater than the length of the screen I want to be able to do an inner scroll of the content itself, while the title (and the card itself) stays in place.

What I've tried is making the card itself a UIStackView, and adding the title as a UILabel. After that, I add a UIScrollView to the stack view, and then add the content to the UIScrollView. The thing I can't figure out is how to tell the UIScrollView that it can grow until the outer stack view reaches its max height (set with a lessThanOrEqualTo constraint) at which point it needs to become scrollable instead.

Here's a crude ascii representation of a shorter amount of content as well as a longer amount of content. Any ideas? Do I need to calculate the size of my content/card container or can I do this with autolayout?

code:

|-------------------|   
| TITLE             |
|                   |
| |---------------| |
| | No            | |
| | Scrolling     | |
| | Required      | |
| |---------------| |
|-------------------|   

|-------------------|   
| TITLE             |
|                   |
| |---------------| |
| | Max           | |
| | Limit         | |
| | Hit           | |
| | So            | |
| | Now           | |
| | Scrolling     | |
| | is            | |
| |---------------| |
|-------------------|   

My guess is you're getting tripped up by the scroll view's not having an intrinsicContentSize, so it ends up having zero height. Try making a UIScrollView subclass, override intrinsicContentSize to return contentSize, and then override contentSize to add a didSet observer that calls invalidateIntrinsicContentSize. Don't forget to set your scroll view to your new subclass.

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