最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

[已解决]iOS中自动布局约束出错:Unable to simultaneously satisfy constraints

iOS crifan 4506浏览 0评论
<code>//
//  ImageBubbleView.swift
//  JianDao
//
//  Created by licrifan on 16/2/26.
//  Copyright © 2016年 licrifan. All rights reserved.
//

import UIKit

class ImageBubbleView: UIView {
    var resMsg:ResourceMessage
   
    var bubbleImageView:UIImageView
   
    var isLoaded:Bool
    var isRefreshed:Bool
    var imageView:UIImageView
   
 //    var refreshImgConstraintGroup:ConstraintGroup

    init(frame:CGRect, resourceMessage:ResourceMessage){
        self.resMsg = resourceMessage

        self.bubbleImageView = UIImageView()
       
        self.isLoaded = false
        self.imageView = UIImageView()
        self.isRefreshed = false

        super.init(frame: frame)

        let placeHolderImageSize = BubbleImagePlaceHolder.size
       
        gLog.debug(&quot;placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)&quot;)
       
        let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType)
        self.bubbleImageView.image = bubbleImage
        self.addSubview(self.bubbleImageView)
        constrain(bubbleImageView) { bubbleImageView in
            bubbleImageView.top == bubbleImageView.superview!.top
            bubbleImageView.left == bubbleImageView.superview!.left
            bubbleImageView.right == bubbleImageView.superview!.right
            bubbleImageView.bottom == bubbleImageView.superview!.bottom
        }
       
        if self.resMsg.fileItem.downloadUrl.isEmpty {
            self.imageView.image = BubbleImagePlaceHolder
            self.bubbleImageView.addSubview(self.imageView)

            constrain(self.imageView) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + 1 + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - 1
                }
                imageView.width == placeHolderImageSize.width
                imageView.height == placeHolderImageSize.height
            }
        } else {
            let cacheKey = self.resMsg.fileItem.id
            let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)!
            gLog.debug(&quot;key=\(cacheKey) for URL=\(downloadUrl)&quot;)
            //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl
            let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey)

            self.imageView.kf_setImageWithResource(
                downloadResource,
                placeholderImage: BubbleImagePlaceHolder,
                optionsInfo: nil,
                progressBlock: { (receivedSize, totalSize) -&gt; () in
                    let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize)
                    gLog.debug(&quot;Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%&quot;)
                },
                //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -&gt; ())
                completionHandler: { (image, error, cacheType, imageURL) -&gt; () in
                    gLog.debug(&quot;image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)&quot;)
                    //image=Optional(&lt;UIImage: 0x7daadc80&gt;, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu)
                   
                    if error != nil {
                        gLog.error(&quot;load image \(self.resMsg.name) error \(error?.localizedDescription)&quot;)
                       
                        self.imageView.image = BubbleImageLoadFail
                    } else {
                        gLog.info(&quot;load image \(self.resMsg.name) completed&quot;)

                        self.isLoaded = true
                       
                        //calculate proper ratio
                        if let curImage = image {
                            let newImageSize = calculateScaledSize(curImage.size, maxSize: BubbleImageMaxSize)
                           
                            constrain(self.imageView) { imageView in
                                imageView.width == newImageSize.width
                                imageView.height == newImageSize.height
                            }
                           
 //                            if !self.isRefreshed {
//                                self.isRefreshed = true
//
//                                self.updateResMsgCell()
//                            }
                        }
                    }
                   
                    dispatchMain_async({
                        self.layoutIfNeeded()
                    })
            })

            self.bubbleImageView.addSubview(self.imageView)
            constrain(imageView) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + 1 + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - 1
                }
            }
        }
    }
   
    required init?(coder aDecoder: NSCoder) {
        fatalError(&quot;init(coder:) has not been implemented&quot;)
    }
   
}
</code>

自动布局的约束出现警告:

<code>2016-04-28 10:06:35.540 JianDao[8985:464975] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
    &quot;&lt;NSLayoutConstraint:0x7b7eeb00 H:[image_placeholder(120)]   (Names: image_placeholder:0x7c831840 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b7eeb40 H:|-(9)-[image_placeholder](LTR)   (Names: image_placeholder:0x7c831840, '|':UIImageView:0x7b285140 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b7c0320 image_placeholder.right == UIImageView:0x7b285140.right - 2   (Names: image_placeholder:0x7c831840 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b796610 H:|-(0)-[UIImageView:0x7b285140](LTR)   (Names: '|':JianDao.ImageBubbleView:0x7c83ebd0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b7d6d90 UIImageView:0x7b285140.right == JianDao.ImageBubbleView:0x7c83ebd0.right&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b7d9b00 H:[JianDao.ImageBubbleView:0x7c83ebd0(&lt;=120)]&gt;&quot;
)

Will attempt to recover by breaking constraint
&lt;NSLayoutConstraint:0x7b7eeb00 H:[image_placeholder(120)]   (Names: image_placeholder:0x7c831840 )&gt;

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in &lt;UIKit/UIView.h&gt; may also be helpful.
</code>

结果改了,还是出错:

<code>2016-04-28 10:24:27.001 [Verbose] [main] [ImageBubbleView.swift:104] init(frame:resourceMessage:) &gt; curImage.size=(750.0, 1378.0), BubbleImageMaxSize=(120.0, 120.0)-&gt; newImageSize=(65.312, 120.0)
2016-04-28 10:24:27.002 JianDao[9298:480875] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
    &quot;&lt;NSLayoutConstraint:0x7b874850 V:|-(10)-[UIButton:0x7b83fc10]   (Names: '|':UITableViewCellContentView:0x7b8317f0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b819f20 V:|-(0)-[UIImageView:0x7b846ac0]   (Names: '|':JianDao.ImageBubbleView:0x78e03510 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b83fbc0 UIImageView:0x7b846ac0.bottom == JianDao.ImageBubbleView:0x78e03510.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x78ec8ce0 JianDao.ImageBubbleView:0x78e03510.top == UIButton:0x7b83fc10.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x78e93960 JianDao.ImageBubbleView:0x78e03510.bottom &lt;= UITableViewCellContentView:0x7b8317f0.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a285620 V:|-(2)-[UIImageView:0x7b870380]   (Names: '|':UIImageView:0x7b846ac0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a688f40 UIImageView:0x7b870380.bottom == UIImageView:0x7b846ac0.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x78fa9170 V:[UIImageView:0x7b870380(120)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a239ad0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b8317f0(130)]&gt;&quot;
)

Will attempt to recover by breaking constraint
&lt;NSLayoutConstraint:0x78fa9170 V:[UIImageView:0x7b870380(120)]&gt;

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in &lt;UIKit/UIView.h&gt; may also be helpful.
</code>

改了代码,结果还是有问题。。。

<code>2016-2016-04-28 10:51:08.664 JianDao[9593:498647] Unable to simultaneously satisfy constraints.
  Probably at least one of the constraints in the following list is one you don't want. 
  Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    &quot;&lt;NSLayoutConstraint:0x79fe3af0 V:|-(10)-[UIButton:0x7a7f35a0]   (Names: '|':UITableViewCellContentView:0x7a7f3a60 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fe6050 V:[UIImageView:0x79fe4790(67.1137)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fe5bd0 V:|-(2)-[UIImageView:0x79fe4790]   (Names: '|':UIImageView:0x79fe46b0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fe6220 UIImageView:0x79fe4790.bottom == UIImageView:0x79fe46b0.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fe49c0 V:|-(0)-[UIImageView:0x79fe46b0]   (Names: '|':JianDao.ImageBubbleView:0x79fe45d0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fe5130 UIImageView:0x79fe46b0.bottom == JianDao.ImageBubbleView:0x79fe45d0.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a7f5a00 JianDao.ImageBubbleView:0x79fe45d0.top == UIButton:0x7a7f35a0.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a7f5a70 JianDao.ImageBubbleView:0x79fe45d0.bottom &lt;= UITableViewCellContentView:0x7a7f3a60.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fb0940 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7a7f3a60(81)]&gt;&quot;
)

Will attempt to recover by breaking constraint 
&lt;NSLayoutConstraint:0x79fe6050 V:[UIImageView:0x79fe4790(67.1137)]&gt;

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in &lt;UIKit/UIView.h&gt; may also be helpful.
</code>

改为:

<code>//
//  ImageBubbleView.swift
//  JianDao
//
//  Created by licrifan on 16/2/26.
//  Copyright © 2016年 licrifan. All rights reserved.
//

import UIKit

class ImageBubbleView: UIView {
    var resMsg:ResourceMessage
   
    var bubbleImageView:UIImageView
   
    var isLoaded:Bool
    var isRefreshed:Bool
    var imageView:UIImageView
   
    var imageViewConstraintGroup:ConstraintGroup
   
 //    var refreshImgConstraintGroup:ConstraintGroup

    init(frame:CGRect, resourceMessage:ResourceMessage){
        self.resMsg = resourceMessage

        self.bubbleImageView = UIImageView()
       
        self.isLoaded = false
        self.imageView = UIImageView()
        self.isRefreshed = false
       
        self.imageViewConstraintGroup = ConstraintGroup()

        super.init(frame: frame)

        let placeHolderImageSize = BubbleImagePlaceHolder.size
       
        gLog.debug(&quot;placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)&quot;)
       
        let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType)
        self.bubbleImageView.image = bubbleImage
        self.addSubview(self.bubbleImageView)
        constrain(bubbleImageView) { bubbleImageView in
            bubbleImageView.top == bubbleImageView.superview!.top
            bubbleImageView.left == bubbleImageView.superview!.left
            bubbleImageView.right == bubbleImageView.superview!.right
            bubbleImageView.bottom == bubbleImageView.superview!.bottom
        }
       
        self.bubbleImageView.addSubview(self.imageView)
       
        if self.resMsg.fileItem.downloadUrl.isEmpty {
            self.imageView.image = BubbleImagePlaceHolder

            self.imageViewConstraintGroup = constrain(self.imageView) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                }

                imageView.width == placeHolderImageSize.width
                imageView.height == placeHolderImageSize.height
            }
        } else {
            let cacheKey = self.resMsg.fileItem.id
            let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)!
            gLog.debug(&quot;key=\(cacheKey) for URL=\(downloadUrl)&quot;)
            //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl
            let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey)

            self.imageView.kf_setImageWithResource(
                downloadResource,
                placeholderImage: BubbleImagePlaceHolder,
                optionsInfo: nil,
                progressBlock: { (receivedSize, totalSize) -&gt; () in
                    let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize)
                    gLog.verbose(&quot;Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%&quot;)
                },
                //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -&gt; ())
                completionHandler: { (image, error, cacheType, imageURL) -&gt; () in
                    gLog.info(&quot;image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)&quot;)
                    //image=Optional(&lt;UIImage: 0x7daadc80&gt;, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu)
                   
                    if error != nil {
                        gLog.error(&quot;load image \(self.resMsg.name) error \(error?.localizedDescription)&quot;)
                       
                        dispatchMain_async({
                            self.imageView.image = BubbleImageLoadFail
                        })
                    } else {
                        gLog.info(&quot;load image \(self.resMsg.name) completed&quot;)

                        self.isLoaded = true
                   
                        //calculate proper ratio
                        if let curImage = image {
                            let newImageSize = calculateScaledSize(curImage.size, maxSize: BubbleImageMaxSize)
                            gLog.verbose(&quot;curImage.size=\(curImage.size), BubbleImageMaxSize=\(BubbleImageMaxSize)-&gt; newImageSize=\(newImageSize)&quot;)
                           
                            constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in
                                imageView.top == imageView.superview!.top + BubbleMargin
                                imageView.bottom == imageView.superview!.bottom - BubbleMargin
                               
                                if self.resMsg.directionType == MessageDirectionType.Receive {
                                    imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                                    imageView.right == imageView.superview!.right - BubbleMargin
                                }else if self.resMsg.directionType == MessageDirectionType.Send {
                                    imageView.left == imageView.superview!.left + BubbleMargin
                                    imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                                }
                               
                                imageView.width == newImageSize.width
                                imageView.height == newImageSize.height
                            }
                           
 //                            if !self.isRefreshed {
//                                self.isRefreshed = true
//
//                                self.updateResMsgCell()
//                            }
                           
                            dispatchMain_async({
                                self.updateConstraintsIfNeeded()
                            })
                        }
                    }
                   
 //                    dispatchMain_async({
//                        self.updateConstraints()
//                        //self.layoutIfNeeded()
//                    })
            })

            self.imageViewConstraintGroup = constrain(imageView) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                }
            }
        }
    }
   
    required init?(coder aDecoder: NSCoder) {
        fatalError(&quot;init(coder:) has not been implemented&quot;)
    }
   
    func updateResMsgCell() {
        if let cellContentView = self.superview {
            gLog.verbose(&quot;cellContentView=\(cellContentView)&quot;)
            //&lt;UITableViewCellContentView: 0x7bf72790; frame = (0 0; 320 130); gestureRecognizers = &lt;NSArray: 0x7bf72cb0&gt;; layer = &lt;CALayer: 0x7bf72860&gt;&gt;
            if let msgTableViewCell = cellContentView.superview {
                gLog.verbose(&quot;msgTableViewCell=\(msgTableViewCell)&quot;)
                //&lt;JianDao.MessageTableViewCell: 0x79a29800; baseClass = UITableViewCell; frame = (0 300; 320 130); hidden = YES; autoresize = W; layer = &lt;CALayer: 0x787a3e30&gt;&gt;
                if let msgTableViewWrapperView = msgTableViewCell.superview {
                    gLog.verbose(&quot;msgTableViewWrapperView=\(msgTableViewWrapperView)&quot;)
                    //&lt;UITableViewWrapperView: 0x7aadee00; frame = (0 0; 320 1200); gestureRecognizers = &lt;NSArray: 0x78ec4400&gt;; layer = &lt;CALayer: 0x78a0abe0&gt;; contentOffset: {0, 0}; contentSize: {320, 1200}&gt;
                    if let msgTableView = msgTableViewWrapperView.superview {
                        gLog.verbose(&quot;msgTableView=\(msgTableView)&quot;)
                        //&lt;UITableView: 0x7c121e00; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = H+BM; gestureRecognizers = &lt;NSArray: 0x7ca445a0&gt;; layer = &lt;CALayer: 0x7cea9a90&gt;; contentOffset: {0, 740}; contentSize: {320, 1609.5}&gt;
                        msgTableView.layoutIfNeeded()
                    }
                }
            }
        }
    }
   
}
</code>

但是还有:

<code>2016-04-28 10:58:45.505 JianDao[9717:505337] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
    &quot;&lt;NSLayoutConstraint:0x7dac0d70 V:|-(10)-[UIButton:0x7b76e0d0]   (Names: '|':UITableViewCellContentView:0x7b7f9e50 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b743010 V:[UIImageView:0x7dac1900(23.229)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b742e10 V:|-(2)-[UIImageView:0x7dac1900]   (Names: '|':UIImageView:0x7dac1820 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b742ec0 UIImageView:0x7dac1900.bottom == UIImageView:0x7dac1820.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7dac1b00 V:|-(0)-[UIImageView:0x7dac1820]   (Names: '|':JianDao.ImageBubbleView:0x7dac1740 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7dac1fd0 UIImageView:0x7dac1820.bottom == JianDao.ImageBubbleView:0x7dac1740.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b743f00 JianDao.ImageBubbleView:0x7dac1740.top == UIButton:0x7b76e0d0.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b743f70 JianDao.ImageBubbleView:0x7dac1740.bottom &lt;= UITableViewCellContentView:0x7b7f9e50.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b7f8380 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b7f9e50(37)]&gt;&quot;
)

Will attempt to recover by breaking constraint
&lt;NSLayoutConstraint:0x7b743010 V:[UIImageView:0x7dac1900(23.229)]&gt;

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in &lt;UIKit/UIView.h&gt; may also be helpful.
</code>

后来调试,看到具体是哪个view了:

<code>2016-04-28 11:08:59.530 JianDao[9821:517584] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
    &quot;&lt;NSLayoutConstraint:0x7b1b8e90 V:|-(10)-[UIButton:0x7b1bc310]   (Names: '|':UITableViewCellContentView:0x7b1baf20 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b1b7820 V:|-(0)-[UIImageView:0x7b1b7b70]   (Names: '|':JianDao.ImageBubbleView:0x7b1b7a90 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b1b6270 UIImageView:0x7b1b7b70.bottom == JianDao.ImageBubbleView:0x7b1b7a90.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f2e430 JianDao.ImageBubbleView:0x7b1b7a90.top == UIButton:0x7b1bc310.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f4d320 JianDao.ImageBubbleView:0x7b1b7a90.bottom &lt;= UITableViewCellContentView:0x7b1baf20.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fc30c0 V:|-(2)-[UIImageView:0x7b1b7c50]   (Names: '|':UIImageView:0x7b1b7b70 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f34090 UIImageView:0x7b1b7c50.bottom == UIImageView:0x7b1b7b70.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f2e400 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b1baf20(44)]&gt;&quot;
)

Will attempt to recover by breaking constraint
&lt;NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]&gt;

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in &lt;UIKit/UIView.h&gt; may also be helpful.
(lldb) po imageView
&lt;UIImageView: 0x7b1b7c50; frame = (10 2; 120 30); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=&lt;CABasicAnimation: 0x7b26c2d0&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26ca50&gt;; position=&lt;CABasicAnimation: 0x7b26cb90&gt;; }; layer = &lt;CALayer: 0x7b1b7d30&gt;&gt; - (null)

(lldb) po imageView.superview
▿ Optional&lt;UIView&gt;
  - Some : &lt;UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=&lt;CABasicAnimation: 0x7b26c300&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26c740&gt;; position=&lt;CABasicAnimation: 0x7b26c960&gt;; }; layer = &lt;CALayer: 0x7b1b8fb0&gt;&gt; - (null)

(lldb) po self.bubbleImageView
&lt;UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=&lt;CABasicAnimation: 0x7b26c300&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26c740&gt;; position=&lt;CABasicAnimation: 0x7b26c960&gt;; }; layer = &lt;CALayer: 0x7b1b8fb0&gt;&gt; - (null)

(lldb) po self
&lt;JianDao.ImageBubbleView: 0x7b1b7a90; frame = (45 10; 132 34); animations = { bounds.origin=&lt;CABasicAnimation: 0x7b26c350&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26c460&gt;; position=&lt;CABasicAnimation: 0x7b26c670&gt;; }; layer = &lt;CALayer: 0x7b1b7d60&gt;&gt;

(lldb) po self.superview
▿ Optional&lt;UIView&gt;
  - Some : &lt;UITableViewCellContentView: 0x7b1baf20; frame = (0 0; 320 44); gestureRecognizers = &lt;NSArray: 0x7b1baac0&gt;; animations = { position=&lt;CABasicAnimation: 0x7b26ae10&gt;; bounds.origin=&lt;CABasicAnimation: 0x7b26afd0&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26b0f0&gt;; }; layer = &lt;CALayer: 0x7b1baff0&gt;&gt;

(lldb) po self.superview?.superview
▿ Optional&lt;UIView&gt;
  - Some : &lt;JianDao.MessageTableViewCell: 0x7937d400; baseClass = UITableViewCell; frame = (0 988; 320 44); autoresize = W; animations = { position=&lt;CABasicAnimation: 0x7b26a8b0&gt;; bounds.origin=&lt;CABasicAnimation: 0x7b26ab10&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26ac20&gt;; }; layer = &lt;CALayer: 0x7b1baef0&gt;&gt;

(lldb) po self.superview?.superview?.superview
▿ Optional&lt;UIView&gt;
  - Some : &lt;UITableViewWrapperView: 0x792ccc00; frame = (0 0; 320 460); gestureRecognizers = &lt;NSArray: 0x79e02e50&gt;; layer = &lt;CALayer: 0x79e2b6d0&gt;; contentOffset: {0, 0}; contentSize: {320, 460}&gt;

(lldb) po self.superview?.superview?.superview?.superview
▿ Optional&lt;UIView&gt;
  - Some : &lt;UITableView: 0x792a1000; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = H+BM; gestureRecognizers = &lt;NSArray: 0x787f89f0&gt;; animations = { bounds.origin=&lt;CABasicAnimation: 0x798342a0&gt;; bounds.size=&lt;CABasicAnimation: 0x798343c0&gt;; }; layer = &lt;CALayer: 0x7b185390&gt;; contentOffset: {0, 768}; contentSize: {320, 2302}&gt;

(lldb) po self.subviews
▿ 1 elements
  - [0] : &lt;UIImageView: 0x7b1b7b70; frame = (0 0; 132 34); opaque = NO; userInteractionEnabled = NO; animations = { bounds.origin=&lt;CABasicAnimation: 0x7b26c300&gt;; bounds.size=&lt;CABasicAnimation: 0x7b26c740&gt;; position=&lt;CABasicAnimation: 0x7b26c960&gt;; }; layer = &lt;CALayer: 0x7b1b8fb0&gt;&gt; - (null)

(lldb) 
</code>

剩下的问题就是:如何看懂约束冲突

how debug Unable to simultaneously satisfy constraints

Auto Layout Guide: Debugging Tricks and Tips

Auto Layout Guide: Visual Format Language

上述的问题中:

<code>    &quot;&lt;NSLayoutConstraint:0x7b1b8e90 V:|-(10)-[UIButton:0x7b1bc310]   (Names: '|':UITableViewCellContentView:0x7b1baf20 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b1b7820 V:|-(0)-[UIImageView:0x7b1b7b70]   (Names: '|':JianDao.ImageBubbleView:0x7b1b7a90 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b1b6270 UIImageView:0x7b1b7b70.bottom == JianDao.ImageBubbleView:0x7b1b7a90.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f2e430 JianDao.ImageBubbleView:0x7b1b7a90.top == UIButton:0x7b1bc310.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f4d320 JianDao.ImageBubbleView:0x7b1b7a90.bottom &lt;= UITableViewCellContentView:0x7b1baf20.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79fc30c0 V:|-(2)-[UIImageView:0x7b1b7c50]   (Names: '|':UIImageView:0x7b1b7b70 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f34090 UIImageView:0x7b1b7c50.bottom == UIImageView:0x7b1b7b70.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x79f2e400 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b1baf20(44)]&gt;&quot;
</code>

最后一个:

UIView-Encapsulated-Layout

是系统主动设置的,是你没法改的-》是系统帮你修正后的结果

-》说明就是这部分有点问题

-》说明此处就是UIView-Encapsulated-Layout-Height中的Height高度出了问题

-》系统自动帮忙把UITableViewCellContentView的高度设置为了44

另外对于Will attempt to recover by breaking constraint的部分,是说系统尝试恢复这部分的问题

而此处的是:

<code>&lt;NSLayoutConstraint:0x7b2ae310 V:[UIImageView:0x7b1b7c50(90.1408)]&gt;
</code>

-》

容易看出:

此处是UIImageView的V=Vertical=高度,设置为了90.1408

-》很明显,和上面系统强制恢复,设置UITableViewCellContentView的高度为44,两者冲突了

-》此处的背景逻辑是:

当前的一些视图属于tableview的cell的content部分:UITableViewCellContentView

UITableViewCellContentView部分的高度只有44

但是内部的一个view:UIImageView,高度却设置为90.1408

-》内部元素高度高于外部父视图的高度,所以冲突了

-》但是其实狠怪异的是:

此处的UITableViewCellContentView的高度

不应该是44的

而应该是

后来多次类似错误:

<code>(
    &quot;&lt;NSLayoutConstraint:0x7d19a4f0 V:|-(10)-[UIButton:0x7be4c080]   (Names: '|':UITableViewCellContentView:0x7be44f30 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7d054610 V:|-(0)-[UIImageView:0x7b92e610]   (Names: '|':JianDao.ImageBubbleView:0x7b9151d0 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7a75a6b0 UIImageView:0x7b92e610.bottom == JianDao.ImageBubbleView:0x7b9151d0.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7d05eec0 JianDao.ImageBubbleView:0x7b9151d0.top == UIButton:0x7be4c080.top&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7d06d2d0 JianDao.ImageBubbleView:0x7b9151d0.bottom &lt;= UITableViewCellContentView:0x7be44f30.bottom&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7beae800 V:|-(2)-[UIImageView:0x7d167cd0]   (Names: '|':UIImageView:0x7b92e610 )&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7be456d0 UIImageView:0x7d167cd0.bottom == UIImageView:0x7b92e610.bottom - 2&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7be46170 V:[UIImageView:0x7d167cd0(67.1137)]&gt;&quot;,
    &quot;&lt;NSLayoutConstraint:0x7d194600 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7be44f30(81)]&gt;&quot;
)

Will attempt to recover by breaking constraint 
&lt;NSLayoutConstraint:0x7be46170 V:[UIImageView:0x7d167cd0(67.1137)]&gt;
</code>

最后改为:

<code>//
//  ImageBubbleView.swift
//  JianDao
//
//  Created by licrifan on 16/2/26.
//  Copyright © 2016年 licrifan. All rights reserved.
//

import UIKit

class ImageBubbleView: UIView {
    var resMsg:ResourceMessage
   
    var bubbleImageView:UIImageView
   
    var isLoaded:Bool
    var isRefreshed:Bool
    var imageView:UIImageView
   
    var imageViewConstraintGroup:ConstraintGroup
   
 //    var refreshImgConstraintGroup:ConstraintGroup

    init(frame:CGRect, resourceMessage:ResourceMessage){
        self.resMsg = resourceMessage

        self.bubbleImageView = UIImageView()
       
        self.isLoaded = false
        self.imageView = UIImageView()
        self.isRefreshed = false
       
        self.imageViewConstraintGroup = ConstraintGroup()

        super.init(frame: frame)

        let placeHolderImageSize = BubbleImagePlaceHolder.size
       
        gLog.debug(&quot;placeHolderImageSize=\(placeHolderImageSize), self.resMsg.fileItem name=\(self.resMsg.fileItem.name), downloadUrl=\(self.resMsg.fileItem.downloadUrl)&quot;)
       
        let bubbleImage = MessageBubbleFactory.bubbleImageForType(self.resMsg.directionType)
        self.bubbleImageView.image = bubbleImage
        self.addSubview(self.bubbleImageView)
        constrain(bubbleImageView) { bubbleImageView in
            bubbleImageView.top == bubbleImageView.superview!.top
            bubbleImageView.left == bubbleImageView.superview!.left
            bubbleImageView.right == bubbleImageView.superview!.right
            bubbleImageView.bottom == bubbleImageView.superview!.bottom
        }
       
        self.bubbleImageView.addSubview(self.imageView)
       
        if self.resMsg.fileItem.downloadUrl.isEmpty {
            self.imageView.image = BubbleImagePlaceHolder

            constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                }

                imageView.width == placeHolderImageSize.width
                imageView.height == placeHolderImageSize.height
            }
        } else {
            let cacheKey = self.resMsg.fileItem.id
            let downloadUrl = NSURL(string: self.resMsg.fileItem.downloadUrl)!
            gLog.debug(&quot;key=\(cacheKey) for URL=\(downloadUrl)&quot;)
            //key=resource-128553c9-8d9b-4053-a134-cb333f2624ee for URL=http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-128553c9-8d9b-4053-a134-cb333f2624ee/download?token=9184uk795a33vnnsbbf4un1msl
            let downloadResource = Resource(downloadURL: downloadUrl, cacheKey: cacheKey)

            self.imageView.kf_setImageWithResource(
                downloadResource,
                placeholderImage: BubbleImagePlaceHolder,
                optionsInfo: nil,
                progressBlock: { (receivedSize, totalSize) -&gt; () in
                    let downloadPercent:Float = 100 * Float(receivedSize) / Float(totalSize)
                    gLog.verbose(&quot;Downloaded: \(receivedSize)/\(totalSize)=\(downloadPercent)%&quot;)
                },
                //((image: Image?, error: NSError?, cacheType: CacheType, imageURL: NSURL?) -&gt; ())
                completionHandler: { (image, error, cacheType, imageURL) -&gt; () in
                    gLog.info(&quot;image=\(image), cacheType=\(cacheType), imageURL=\(imageURL)&quot;)
                    //image=Optional(&lt;UIImage: 0x7daadc80&gt;, {747, 495}), cacheType=Memory, imageURL=Optional(http://dev.jiandao.im:8080/user/user-e6882cab-cedf-4335-9b7c-612cd5b4d37d/received/resource-27ddfda6-c33a-49cf-8941-e7cf7151a686/download?token=ecn9jo4dbvua2ua1j2h56rsbnu)
                   
                    if (error != nil) || (image == nil) {
                        gLog.error(&quot;load \(image) for \(self.resMsg.name) error \(error?.localizedDescription)&quot;)
                       
                        dispatchMain_async({
                            self.imageView.image = BubbleImageLoadFail
                        })

                        return
                    }

                    gLog.info(&quot;load image \(self.resMsg.name) completed&quot;)
                    self.isLoaded = true
               
                    //calculate proper ratio
                    let newImageSize = calculateScaledSize(image!.size, maxSize: BubbleImageMaxSize)
                    gLog.verbose(&quot;image.size=\(image!.size), BubbleImageMaxSize=\(BubbleImageMaxSize)-&gt; newImageSize=\(newImageSize)&quot;)

                    dispatchMain_async({
                        constrain(self.imageView, replace: self.imageViewConstraintGroup) { imageView in
                            imageView.top == imageView.superview!.top + BubbleMargin
                            imageView.bottom == imageView.superview!.bottom - BubbleMargin
                           
                            if self.resMsg.directionType == MessageDirectionType.Receive {
                                imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                                imageView.right == imageView.superview!.right - BubbleMargin
                            }else if self.resMsg.directionType == MessageDirectionType.Send {
                                imageView.left == imageView.superview!.left + BubbleMargin
                                imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                            }
                           
                            imageView.width == newImageSize.width
                            imageView.height == newImageSize.height
                        }
                       
                        self.updateConstraintsIfNeeded()
                        self.layoutIfNeeded()
//                      self.updateResMsgCell()
                    })
                })

            constrain(imageView, replace: self.imageViewConstraintGroup) { imageView in
                imageView.top == imageView.superview!.top + BubbleMargin
                imageView.bottom == imageView.superview!.bottom - BubbleMargin

                if self.resMsg.directionType == MessageDirectionType.Receive {
                    imageView.left == imageView.superview!.left + BubbleMargin + BubbleArrowWidth
                    imageView.right == imageView.superview!.right - BubbleMargin
                }else if self.resMsg.directionType == MessageDirectionType.Send {
                    imageView.left == imageView.superview!.left + BubbleMargin
                    imageView.right == imageView.superview!.right - BubbleArrowWidth - BubbleMargin
                }
            }
        }
    }
   
    required init?(coder aDecoder: NSCoder) {
        fatalError(&quot;init(coder:) has not been implemented&quot;)
    }
   
}
</code>

基本上解决了此处的约束警告了。

转载请注明:在路上 » [已解决]iOS中自动布局约束出错:Unable to simultaneously satisfy constraints

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
90 queries in 0.205 seconds, using 22.28MB memory