Subview's image not displaying

I have 8 UIViews that represent levels in my app. For each such view:
If the user has unlocked, but not completed the level, the view displays a button.
If the user has unlocked and completed the level, the view displays an image.
Otherwise, the view displays nothing.

At least, that's how it's supposed to work. In reality, there is one view that displays nothing even if I complete the level it represents. The other views work just well. However, this is the only one of the 8 views that I created in code (due to a prior problem with the view's button, which went away when I switched to using code).
Here is the view's code:

A few things I've checked:
1) The image view's frame - it's what it should be
2) If the image view's set to hidden when it shouldn't be - it's not.
Edit: Also of note, the image URL is unwrapped with a ! so it's clearly not that.

1) When I go to the view debugger, the problem image view doesn't show up, either in the view screen or in the left pane.
2) When I check the image view's superview from update(), I get "nil"
Edit: I do this to add the superview:

1) When I go to the view debugger, the problem image view doesn't show up, either in the view screen or in the left pane.
2) When I check the image view's superview from update(), I get "nil"
Should I show you my viewWillAppear method?

I suggest a first step is to add some logging to your viewWillAppear method, and ensure that the text you log actually shows up as output. In short, confirm your expectation.

If this seems obvious, and you already have confirmation that the view is actually being added, then break the problem down into smaller steps. Add logging (or some other confirmable result) in each function that should be getting called. Then confirm that each function is called, by looking for the logged output.

Another strategy is to use the debugger and set a breakpoint on the custom view's viewWillAppear func. If the breakpoint is hit, look at the context. If the breakpoint isn't hit, think of other ways you might confirm that the custom view is getting added correctly.

What you're doing with the logging or breakpoints is applying the Break It Down principle to the time-ordered sequence of expected function calls. There are several funcs that are expected to be called. Confirm that the earliest of these is actually being called. If it's not, work backwards in the calling sequence to another point you expect something to happen. Put a confirmation there (breakpoint or log). Repeat, moving earlier in the sequence of calls, until you get at least one confirmation. Then move later in the expected sequence.

UPDATE: When I put a breakpoint after addSubview in my didSet method, I get these logging statements from all the menu item views:

Quote

(UIView?) $R0 = 0x16ed5b40 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R1 = 0x16ed7900 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R2 = 0x16eda130 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R3 = 0x16edc3b0 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R4 = 0x16da72f0 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R5 = 0x16da9850 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R6 = 0x16dabff0 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R7 = 0x16dae790 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R8 = 0x16db0f30 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R9 = 0x16edeba0 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R10 = 0x16ee1500 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

(UIView?) $R11 = 0x16ee3830 {

UIKit.UIResponder = {

ObjectiveC.NSObject = {}

}

}

Click to expand...

--- Post Merged, Mar 1, 2017 ---

Fixed it! Lesson learned: If I'm going to create and configure a view manually, it's best to do both the creating and the configuring in one function. In other words: Don't use didSet to add a subview to a view (in this case, that subview is the image view), initWithFrame to create the subview, etc.

UPDATE: When I put a breakpoint after addSubview in my didSet method, I get these logging statements from all the menu item views:

--- Post Merged, Mar 1, 2017 ---

Fixed it! Lesson learned: If I'm going to create and configure a view manually, it's best to do both the creating and the configuring in one function. In other words: Don't use didSet to add a subview to a view (in this case, that subview is the image view), initWithFrame to create the subview, etc.

What did you expect to happen? What actually happened?
In short, describe your expectation and your confirmation.

In general, do not create, init, or add subviews in the viewWillAppear method. Only create, init, or add subviews within a create or init method.

When you create, init, or add subviews in viewWillAppear, then you become responsible for the life-cycle calls to those subviews. In particular, you become responsible for calling viewWillAppear on the subviews.

This is the second thread you've asked essentially the same question. From what I see I think you don't really understand the iOS view methods or how they are called and stacked in their que as subviews.

From reading you question I found it rather easy, using story board, to code in some buttons using subviews place on the main view. Here's the code for the ViewController (Objective C).

When you create, init, or add subviews in viewWillAppear, then you become responsible for the life-cycle calls to those subviews. In particular, you become responsible for calling viewWillAppear on the subviews.

Click to expand...

really isn't completely true. The subviews remain attached to the view and will update when the view is called and will die when the main view is killed (unless you retain the subview). iOS takes care of this stuff.

"When the actual content of your view changes, it is your responsibility to notify the system that your view needs to be redrawn. You do this by calling your view’s setNeedsDisplay() or setNeedsDisplay(_ method of the view. These methods let the system know that it should update the view during the next drawing cycle. Because it waits until the next drawing cycle to update the view, you can call these methods on multiple views to update them at the same time." From Apple documentation

Essentially the adding of a subview causes it to appear, but don't forget there may be more than one subview and only the one on top is in view (unless it is also transparent in color, which I also use).

OK I went back to the beginning of this thread and I believe what you want to do is a game with an intial menu which opens up a new UIView as one progresses through the levels, like "Angry Birds."

So why aren't you using a simpler method than building buttons from code?

I would have maintained a user file (NSUserDefaults) that simply saves a Boolean value for each level in you app that is achieved. As each level is reached just enable the UIButton associated with the next view. Use messaging to inform and update the user defaults and button when the level is completed and the ready to move to the next.

Each UIButton on your inital UIView can easily be linked (segued) to the next UIViewController (and associated UIView) of the level. Of you're worried about memory control this method is managed much better by the API than building each UIView and UIButton on the fly.

The best part of the "segued" system is you can give the segue and identifier and then call it later with

MacRumors attracts a broad audience
of both consumers and professionals interested in
the latest technologies and products. We also boast an active community focused on
purchasing decisions and technical aspects of the iPhone, iPod, iPad, and Mac platforms.